大一下半期数据结构
知识点
递归算法虽然简单,但一般而言,其执行效率并不高。对于二叉树的遍历操作,可以仿照递归算法执行过程中工作栈的状态变化得到非递归算法。
一、前序遍历非递归算法
二叉树前序遍历非递归算法的关键是:在前序遍历过某结点的整个左子树后,如何找到该结点的右子树的根指针,对于图一二叉树
工作栈S和当前根指针bt的变化情况以及树中各结点的访问次序。
分析二叉树前序遍历的执行过程可以看出,在访问某结点后,应将该结点的指针保存在栈中,以便以后能通过它找到
该结点的右子树。一般情况下,在前序遍历中,设要遍历二叉树的根指针为bt,可能有两种情况:
(1)若bt!=NULL,则表明当前二叉树不为空,此时,应输出根结点bt的值并将bt保存到栈中,准备继续遍历bt的
左子树。
(2)若bt==NULL,则表明以bt为根指针的二叉树遍历完毕,并且bt是栈顶指针所指结点的左子树。若栈不为空,应根据栈顶指针所指结点找到待遍历右子树的根指针并赋予bt,以继续遍历下去:若栈为空,则表明整个二叉树遍历完毕,应结束。
二叉树前序遍历的非递归算法
void PreorderTraversal( BiNode *root )//( BinTree BT )BinTree 为结构体指针,BiNode 为结构体类型
//二叉链表的根指针root
{
BiNode *bt=root,*S[MaxSize];//定义顺序栈,工作指针bt初始化
int top=-1;//初始化顺序栈
while(bt!=NULL||top!=-1)//两个条件都不成立才退出循环
{
while(bt!=NULL)//当bt不空时循环
{
printf(" %c",bt->Data);//输出bt->data
S[++top]=bt;//将指针bt保存到栈中
bt=bt->lchild;//遍历bt的左子树
}
if(top!=-1)如果栈S不空,则
{
bt=S[top--];//将栈顶元素弹出至bt
bt=bt->rchild;//准备遍历bt的右子树
}
}
}
void PreorderTraversal( BinTree BT )
{
Stack s=CreateStack();
//Push(s,BT);
BinTree now=BT;
if(now!=NULL)
Push(s,now);
while(!IsEmpty(s))
{ now=Pop(s);
printf(" %c",now->Data);
if(now->Right!=NULL)
Push(s,now->Right);
if(now->Left!=NULL)
Push(s,now->Left);
}
}
中序遍历非递归算法
在中序遍历过程中遇到某结点不能立即访问它,而是将它压栈,等到它的左子树遍历完毕后,再从栈中弹出并访问之。
void InorderTraversal( BiNode *root )//( BinTree BT )BinTree 为结构体指针,BiNode 为结构体类型
//二叉链表的根指针root
{
BiNode *bt=root,*S[MaxSize];//定义顺序栈,工作指针bt初始化
int top=-1;//初始化顺序栈
while(bt!=NULL||top!=-1)//两个条件都不成立才退出循环
{
while(bt!=NULL)//当bt不空时循环
{
S[++top]=bt;//将指针bt保存到栈中
bt=bt->lchild;//遍历bt的左子树
}
if(top!=-1)如果栈S不空,则
{
bt=S[top--];//将栈顶元素弹出至bt
printf(" %c",bt->Data);//输出bt->data
bt=bt->rchild;//准备遍历bt的右子树
}
}
}
void InorderTraversal( BinTree BT )
{ Stack s=CreateStack();
if(BT!=NULL)
Push(s,BT);
BinTree now;
while(!IsEmpty(s))
{ while(Peek(s)->Left!=NULL)
Push(s,Peek(s)->Left);
while(!IsEmpty(s))
{ now=Peek(s);
printf(" %c",now->Data);
Pop(s);
if(now->Right!=NULL)
{ Push(s,now->Right);
break;
}
}
}
}
后序遍历非递归算法
当遍历完左子树,由于右子树尚未遍历,因此栈顶结点不能出栈,通过栈顶结点找到它的右子树,准备遍历它的右子树:当遍历完右子树,将栈顶结点出栈,并访问它。
为了区别对栈顶结点的不同处理,设置标志变量flag,flag=1表示遍历完左子树,栈顶结点不能出栈:flag=2表示遍历完右子树,栈顶结点可以出栈并访问。可以用c语言中的结构体类型来定义栈元素类型
typedef struct{
BiNode *ptr;
int flag;
}ElemType;//BiNode 为结构体类型
设要遍历二叉树的根指针为bt,则有以下两种情况:
(1)若bt不等于NULL,则bt及标志flag(置为1)入栈,遍历其左子树。
(2)若bt等于NULL,此时栈为空,则整个遍历结束:若栈不为空,则表明栈顶结点的左子树或右子树已遍历完毕。若栈顶结点的标志flag=1,则表明栈顶结点的左子树以遍历完毕,将flag改为2,并遍历栈顶结点的右子树:若栈顶结点的标志flag=2,则表明栈顶结点的右子树也遍历完毕,出栈并输出栈顶结点。
void PostorderTraversal(BiNode *root )
{
ElemType S[MaxSize];//定义顺序栈
int top=-1;初始化顺序栈
BiNode *bt=root;//工作指针bt初始化
while(bt!=NULL||top!=-1)//循环直到bt为空且栈S为空
{
while(bt!=NULL)
{
top++;
S[top].ptr=bt;//root连同标志flag入栈
S[top].flag=1;
bt=bt->lchild;//继续遍历bt的左子树
}
while(top!=-1&&S[top].flag==2)//注意是循环,可能连续出栈
//当栈S非空且栈顶元素的标志为2时,出栈并输出栈顶结点
{
bt=S[top--].ptr;
printf(" %c",bt->Data);
}
if(top!=-1)//当栈非空,将栈顶元素的标志改为2,准备遍历栈顶结点的右子树
{
S[top].flag=2;
bt=S[top].ptr->rchild;
}
}
}
void PostorderTraversal( BinTree BT )
{ Stack s=CreateStack();
if(BT!=NULL)
Push(s,BT);
BinTree now=BT,last=NULL;
while(!IsEmpty(s))
{ while(Peek(s)->Left!=NULL)
Push(s,Peek(s)->Left);
while(!IsEmpty(s))
{ now=Peek(s);
if(now->Right==last||now->Right==NULL)
{ printf(" %c",now->Data);
Pop(s);
last=now;
}
else
{ Push(s,now->Right);
break;
}
}
}
}
添加链接描述
附大神博客地址