您的位置:首页 > 其它

二叉树的遍历(前中后,层次)——legend

2014-08-19 14:26 232 查看

二叉树的遍历:traverse

 (1)深度优先遍历 :(递归与非递归)

  (1.1)先序 (先根):preOrder(WithRecusion/WithoutRecusion)

  (1.2)中序 (中根):inOrder(WithRecusion/WithoutRecusion)

  (1.3)后序 (后根):postOrder(WithRecusion/WithoutRecusion)

(注意:非递归的深度优先遍历中:栈中的字段有top,以及节点指针数组BTNode* array[Maxsize]   )

----

 (2)广度优先遍历 :

  (2.1)层次遍历 :leverOrder

(注意:层次遍历中队列中的字段有 front ,rear  以及 节点指针数组 BTNode* array[Maxsize]  )

1.如果在队列中加入一个字段 int levelArray[Maxsize]可以记录下每个节点的层次。

2.如果在队列中的的数组的每个元素为typedef struct Element { BTNode * pnode ,int parentIndex};(parentIndex表示当前节点pnode的父节点所在的下标)

然后队列为{ front ,rear,  Element array[Maxsize]  },则可以根据由某个节点快速的查找到父节点,对于查找路径方便。

-----

(3)祖先节点与 到根节点的路径:

 ---------------------------------

 (一)先序:先访根节点,再访问左子树,再访问右子树。

 (1)递归:

 void PreOrder(BTNode* b){

  if(b!=NULL){

   visit(b->data);

   PreOrder(b->lchild);

   PreOrder(b->rchild);

  }

 }

 (2)非递归:

 思想:先根,然后左子树,然后右子树。

 所以:先将根节点进栈,在栈非空时循环:出栈p,访问p,将其右孩子节点进栈,再左孩子节点接栈。

 void preOrder(BTNode *b){

  BTNode*  stack[Maxsize];

  BTNode * p;

  int top=-1;

  if(b!=NULL){

   top++;

   stack[top]=b;//根节点进栈

   while(top>-1){

   //栈非空

   p=stack[top];

   top--;//出栈

   visit(p->data);//访问

    if(p->rchild!=NULL){

    //右孩子非空,则进栈

    top++;

    stack[top]=p->rchild;

    }

//必须先判断右子树,然后再判断左子树,右孩子先进栈。

    if(p->lchild!=NULL){

    //左孩子非空,则进栈

    top++;

    stack[top]=p->lchild;

    }

   }

  }

 }

注意:非递归的先序遍历中,必须是先是右孩子进栈,然后孩子进栈,顺序不可以颠倒,否则就是根右左。

-----------

(二)中序:先左子树,然后跟节点,然后右子树。

(1)递归:

void inOrder(BTNode * b){

 if(b!=NULL){

 inOrder(b->lchild);

 visit(b->data);

 inOrder(b->rchild);

 }

}

(2)非递归:

思想:

1)先扫描根节点的所有左节点并将它们一一压栈,

2)然后出栈一个节点p,当前新出栈的节点p必然没有左孩子或者左孩子以及被访问过,然后访问节点p,

3)然后扫描节点p的右孩子,然后将p的右孩子的所有左孩子一一压栈,与1)重复,直至栈空。

   void inOrder(BTNode * b){

    BTNode* stack[Maxsize];

    BTNode* p;

    int top=-1;

    if(b!=NULL){

     p=b;

      while(p!=NULL || top>-1){

        while(p){

        //根节点p的左孩子不断进栈

        top++;

        stack[top]=p;

        p=p->lchild;

        }

        if(top>-1){

        //栈非空时

        p=stack[top];

        top--;//出栈

        visit(p->data);//访问

        p=p->rchild;//p的右子树作为新的p,让p的右子树的左孩子逐个进栈

        }

      }

    }

   }

   -----------

   (三)后续:先左子树,然后右子树,然后根节点。

   (1)递归:

    void postOrder(BTNode *b){

     if(b){

     postOrder(b->lchild);

     postOrder(b->rchild);

     visit(b->data);

     }

    }

   (2)非递归:

   思想:

   1)先扫描一个根节点的所有的左孩子并一一进栈

   2)出栈一个节点p,然后扫描节点p的右孩子并进栈,在扫描p的右孩子的所有左孩子并一一进栈。即将p的右孩子作为1)中的跟节点,重复1)

   3)当一个节点的左右孩子均访问过,才访问该节点。直至栈空。

难点:如何判断节点p的右孩子已经访问过了,用q保存右子树中刚刚访问过的节点(初值为null),若p->rchild=q,说明p节点的左右子树都已经访问过了,然后就可以访问p了。如果不成立,说明p的右子树没有访问完。

void postOrder(BTNode *b){

 BTNode* stack[Maxsize];

 BTNode* p=b,*pre;

 int flag,top=-1;

 if(b){

  do{

   while(p){//节点p的所有左孩子进栈

   top++;

   stack[top]=p;

   p=p->lchild;

   }

   pre=NULL;//pre指向栈顶节点前一个已经访问过的节点。

   flag=1;

   while(top!=-1 && flag==1){

    p=stack[top];//取栈顶,但不出栈

    if(p->rchild==pre){

    top--;//出栈

    visit(p->data);//访问

    pre=p;//更新已经访问过的 节点。

    }

    else{

    //否则将p节点的右孩子的所有左孩子进栈。

    p=p->rchild;

    flag=0;//跳出当前循环

    }

   }

  }while(top!=-1);

 }

}

---------------

(四)层次遍历:levelOrder

#include "queue.h"

void levelOrder(BTNode * T){

 BTNode * p;

 Queue Q;

 initQueue(Q);

 enQueue(Q,T);

 while(!isEmpty(Q)){

 deQueue(Q,p);

 visit(p->data);

 if(p->lchild) enQueue(Q,p->lchild);

 if(p->rchild)  enQueue(Q,p->rchild);

 }

}

或者:

void levelOrder(BTNode* b){

 BTNode* queue[Maxsize];

 int front=rear=-1;

 BTNode* pnode;

 rear++;

 queue[rear]=b;//进队

 while(rear!=front){//队列非空

 front=(front+1)%Maxsize;

 pnode=queue[front];//出队

 visit(pnode->data);//访问

 if(pnode->lchild) {

 rear++;

 queue[rear]=pnode->lchild;//左孩子进队

 }

 if(pnode->rchild) {

 rear++;

 queue[rear]=pnode->rchild;//右孩子进队

 }

 }

}

---------

(5)补充:路径与祖先节点。

1.某个节点的祖先节点 即 从该节点到根节点的路径;

2. 非递归的后序遍历中,栈中栈顶节点的下面的节点为栈顶节点的祖先节点,,即  将栈 中各个元素出栈可以得到栈顶节点到根结点的路径。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二叉树
相关文章推荐