二叉树的非递归遍历

来源:互联网 发布:淘宝上的希爱力能买吗 编辑:程序博客网 时间:2024/05/21 09:49

来至:http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html

http://blog.csdn.net/xiaoshi935/article/details/4500372

  二叉树的非递归遍历

         二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的。对于二叉树,有前序、中序以及后序三种遍历方法。因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。在三种遍历中,前序和中序遍历的非递归算法都很容易实现,非递归后序遍历实现起来相对来说要难一点。

一.前序遍历

   前序遍历按照“根结点-左孩子-右孩子”的顺序进行访问。

   1.递归实现

复制代码
void preOrder1(BinTree *root)     //递归前序遍历 {    if(root!=NULL)    {        cout<<root->data<<" ";        preOrder1(root->lchild);        preOrder1(root->rchild);    }}
复制代码

   2.非递归实现

    根据前序遍历访问的顺序,优先访问根结点,然后再分别访问左孩子和右孩子。即对于任一结点,其可看做是根结点,因此可以直接访问,访问完之后,若其左孩子不为空,按相同规则访问它的左子树;当访问其左子树时,再访问它的右子树。因此其处理过程如下:

     对于任一结点P:

     1)访问结点P,并将结点P入栈;

     2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P;

     3)直到P为NULL并且栈为空,则遍历结束。

复制代码
void preOrder2(BinTree *root)     //非递归前序遍历 {    stack<BinTree*> s;    BinTree *p=root;    while(p!=NULL||!s.empty())    {        while(p!=NULL)        {            cout<<p->data<<" ";            s.push(p);            p=p->lchild;        }        if(!s.empty())        {            p=s.top();            s.pop();            p=p->rchild;        }    }}
复制代码

二.中序遍历

    中序遍历按照“左孩子-根结点-右孩子”的顺序进行访问。

    1.递归实现

复制代码
void inOrder1(BinTree *root)      //递归中序遍历{    if(root!=NULL)    {        inOrder1(root->lchild);        cout<<root->data<<" ";        inOrder1(root->rchild);    }} 
复制代码

   2.非递归实现

    根据中序遍历的顺序,对于任一结点,优先访问其左孩子,而左孩子结点又可以看做一根结点,然后继续访问其左孩子结点,直到遇到左孩子结点为空的结点才进行访问,然后按相同的规则访问其右子树。因此其处理过程如下:

   对于任一结点P,

  1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;

  2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;

  3)直到P为NULL并且栈为空则遍历结束

复制代码
void inOrder2(BinTree *root)      //非递归中序遍历{    stack<BinTree*> s;    BinTree *p=root;    while(p!=NULL||!s.empty())    {        while(p!=NULL)        {            s.push(p);            p=p->lchild;        }        if(!s.empty())        {            p=s.top();            cout<<p->data<<" ";            s.pop();            p=p->rchild;        }    }    } 
复制代码

  三.后序遍历

      后序遍历按照“左孩子-右孩子-根结点”的顺序进行访问。

      1.递归实现

复制代码
void postOrder1(BinTree *root)    //递归后序遍历{    if(root!=NULL)    {        postOrder1(root->lchild);        postOrder1(root->rchild);        cout<<root->data<<" ";    }    } 
复制代码

      2.非递归实现

       后序遍历的非递归实现是三种遍历方式中最难的一种。因为在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点,这就为流程的控制带来了难题。下面介绍两种思路。

      第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。

复制代码
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;            }        }    }    } 
复制代码

        第二种思路:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

复制代码
void postOrder3(BinTree *root)     //非递归后序遍历{    stack<BinTree*> s;    BinTree *cur;                      //当前结点     BinTree *pre=NULL;                 //前一次访问的结点     s.push(root);    while(!s.empty())    {        cur=s.top();        if((cur->lchild==NULL&&cur->rchild==NULL)||           (pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))        {            cout<<cur->data<<" ";  //如果当前结点没有孩子结点或者孩子节点都已被访问过               s.pop();            pre=cur;         }        else        {            if(cur->rchild!=NULL)                s.push(cur->rchild);            if(cur->lchild!=NULL)                    s.push(cur->lchild);        }    }    }
复制代码
我自己把整理了一下(综合了一下):


#define STACK_INT_SIZE 100  //存储空间初始分配量  #define STACKINCREMENT 10 //存储空间分配增量  #define ok 1  #define ERROR 0  #define TRUE 1  #define FALSE 0  typedef char TElemType;typedef int Status;typedef char SElemType;typedef struct BiTNode{TElemType data;struct BiTNode *Lchild,*rchild;}BiTNode,*BiTree;typedef struct{//栈的存储方式BiTree *base;//base为指向BiTree型的指针BiTree *top;int stacksize;//当前已分配的存储空间 }SqStack;typedef struct node1{BiTree btnode;bool isFirst;}*BTNode;int INitStack(SqStack &s){s.base=(BiTree *)malloc(sizeof(BiTree));if(!s.base){exit(OVERFLOW);}else{s.top=s.base;s.stacksize=STACK_INT_SIZE;return ok;}} int GetTop(SqStack &s,BiTree &e){if(s.top==s.base){return ERROR;}else{e=*(s.top-1);return ok;}}int Push(SqStack &s,BiTree e){if(s.top-s.base >= s.stacksize){s.base=(BiTree *)realloc(s.base,(s.stacksize+STACKINCREMENT)*sizeof(BiTree));if(!s.base){return ERROR;}else{s.top=s.base+s.stacksize;s.stacksize+=STACKINCREMENT;}}*s.top=e;s.top++;return ok;} int Pop(SqStack &s, BiTree &e) { if(s.base==s.top) { return ERROR; } s.top--; e=*s.top; return ok; } int StackEmpty(SqStack s) {if(s.top==s.base){return TRUE;} else { return FALSE; } }int CreatBiTree(BiTree &T){char ch;scanf("%c",&ch);if(ch=='0'){T=NULL;}else{if(!(T=(BiTNode *)malloc(sizeof(BiTNode)))){exit(OVERFLOW);}T->data=ch;CreatBiTree(T->Lchild);CreatBiTree(T->rchild);}return ok;}void InOrderTraverse(BiTree T)//中序递归遍历{if(T != NULL){InOrderTraverse(T->Lchild);cout<<T->data<<" ";InOrderTraverse(T->rchild);}}int INOrderTraverse(BiTree T)//中序非递归遍历{SqStack s;INitStack(s);BiTree p;p=T;while(p || !StackEmpty(s)){if(p){Push(s,p);p=p->Lchild;}else{Pop(s,p);printf(" %c ",p->data);p=p->rchild;}}return ok;}void preOrder1(BiTree T) //前序递归遍历{if(T != NULL){cout<<T->data<<" ";preOrder1(T->Lchild);preOrder1(T->rchild);}}void preOrder2(BiTree T) //前序非递归遍历{SqStack s;INitStack(s);BiTree p=T;while(p != NULL || !StackEmpty(s)){while( p!= NULL){cout<<p->data<<" ";Push(s,p);p=p->Lchild;}if(!StackEmpty(s)){Pop(s,p);p=p->rchild;}}}void PostOrder1(BiTree T)//后序递归遍历{if(T){PostOrder1(T->Lchild);PostOrder1(T->rchild);cout<<T->data<<" ";}}void PostOrder2(BiTree T)   //后序非递归遍历(思路1){BiTree p=T;SqStack s;INitStack(s);BTNode temp;temp=(BTNode)malloc(sizeof(node1));BTNode btn=(BTNode)malloc(sizeof(node1));while(p != NULL || !StackEmpty(s)){while(p != NULL){btn->btnode=p;btn->isFirst=true;Push(s,btn->btnode);p=p->Lchild;}if(!StackEmpty(s)){Pop(s,temp->btnode);if(temp->isFirst==true){temp->isFirst=false;Push(s,temp->btnode);p=temp->btnode->rchild;}else{cout<<temp->btnode->data<<" ";p=NULL;}}}}void PostOrder3(BiTree T)   //后序非递归遍历(思路2){BiTree cur,pre=NULL,p;SqStack s;INitStack(s);Push(s,T);while(!StackEmpty(s)){GetTop(s,cur);if((cur->Lchild==NULL && cur->rchild == NULL) ||(pre != NULL && (pre==cur->Lchild || pre==cur->rchild))){cout<<cur->data<<" ";Pop(s,p);pre=cur;}else{if(cur->rchild != NULL){Push(s,cur->rchild);}if(cur->Lchild !=NULL){Push(s,cur->Lchild);}}}}int main(){printf("请输入先序建立二叉树所需要的数据(例如ABD0000):");BiTree t;CreatBiTree(t);printf("递归前序输出为:");preOrder1(t);printf("\n非递归前序输出为:");preOrder2(t);printf("\n中序递归输出为:");InOrderTraverse(t);printf("\n中序非递归输出为:");INOrderTraverse(t);printf("\n后序递归输出为:");PostOrder1(t);printf("\n后序非递归(1)输出为:");PostOrder2(t);printf("\n后序非递归(2)输出为:");PostOrder3(t);printf("\n");return 0;}

有问题的地方还请各位指出哈。。。

0 0
原创粉丝点击