一、 先序遍历:
1、递归算法: 根左右
int PreOrder(BiTree p) /* 先序遍历二叉树*/
{
if ( p!= NULL )
{
printf("%c", p->data);
PreOrder( p->lchild ) ;
PreOrder( p->rchild) ;
}
return num;
}
2、非递归算法
利用 栈 先进后出的特点,应该先入栈右孩子,再入栈左孩子
(1)、首先输出根节点
(2)、判断右孩子是否为空,若不为空,入栈;判断左孩子是否为空,若不为空,入栈;
(3)、如果(2)的两个条件都不满足,说明为叶子节点,指针指向该节点,等待(1)的输出
void Preorder_n(BiTree p){ /*先序遍历的非递归算法*/
BiTree stack[MAX],q;
int top=0,i;
for(i=0;i<MAX;i++)
stack[i]=NULL;/*初始化栈*/
q=p;
while(q!=NULL){
printf("%c",q->data);
if(q->rchild!=NULL)
stack[top++]=q->rchild;
if(q->lchild!=NULL)
q=q->lchild;
else if(top>0)
q=stack[--top];
else
q=NULL;
}
}
二、中序遍历:
1、递归算法: 左根右
void InOrder(BiTree p) /* 中序遍历二叉树*/
{
if( p!= NULL )
{
InOrder( p->lchild ) ;
printf("%c", p->data);
InOrder( p->rchild) ;
}
}
2、非递归算法(同样利用了 栈 的特性)
(1)、只要左子树存在,则结点指向左子树,将这些结点持续循环的入栈。
(2)、当节点的左孩子不存在时,应该输出该节点的值;
(3)、结点在完成左孩子和自身后,将指针指向右子树,若右子树不为空,再去判断该节点的左孩子
void Inorder_n(BiTree p) /*中序遍历的非递归算法*/
{
BiTree stack[MAX],q;
int top=0,i;
for(i=0; i<MAX; i++) stack[i]=NULL; /*初始化栈*/
q=p;
do
{
while(q!=NULL)
{
stack[top++]=q;
q=q->lchild;
}
if(top>0)
{
q=stack[top-1];
printf("%c",stack[top-1]->data);
top--;
q=q->rchild;
}
}while(top!=0||q!=NULL);
}
三、后序遍历
1、递归算法:左右根
void PostOrder(BiTree p) /* 后序遍历二叉树*/
{
if ( p!= NULL )
{
PostOrder( p->lchild ) ;
PostOrder( p->rchild) ;
printf("%c", p->data);
}
}
2、非递归算法
在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点
两种方法:
(1)、第一种方法:
(1)、对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问, 因此其右孩子还未被访问。
(2)、按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。
可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是 否是第一次出现在栈顶。
void postOrder2(BinTree *root) //非递归后序遍历
{
stack<BTNode*> s;
BinTree *p=root;
BTNode *temp;
while(p!=NULL||!s.empty())
{
while(p!=NULL) //沿左子树一直往下搜索,直至出现没有左子树的结点
{
BTNode *btn=(BTNode *)malloc(sizeof(BTNode));
btn->btnode=p;
btn->isFirst=true;
s.push(btn);
p=p->lchild;
}
if(!s.empty())
{
temp=s.top();
s.pop();
if(temp->isFirst==true) //表示是第一次出现在栈顶
{
temp->isFirst=false;
s.push(temp);
p=temp->btnode->rchild;
}
else //第二次出现在栈顶
{
cout<<temp->btnode->data<<" ";
p=NULL;
}
}
}
}
(2)、第二种方法:
(1)、对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存 在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。
(2)、若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了 每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
void Postorder_n(BiTree p) /*后序遍历的非递归算法*/
{
BiTree stack[MAX],q,T; // T代表的上一次访问的节点,q 是当前访问节点
int top=0,i;
T=NULL;
for(i=0; i<MAX; i++) stack[i]=NULL; /*初始化栈*/
q=p;
stack[top++]=p; // 先将根节点入栈
while(top!=0)
{
q=stack[top-1];
if((q->lchild==NULL&&q->rchild==NULL)||
(T!=NULL)&&(T==q->lchild||T==q->rchild))
{
printf("%c",stack[top-1]->data);
top--;
T=q;
}
else
{
if(q->rchild!=NULL) // 先入栈的后出栈,则先压进去右孩子
stack[top++]=q->rchild;
if(q->lchild!=NULL)
stack[top++]=q->lchild;
}
}
}