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

来源:互联网 发布:java 三大特性 编辑:程序博客网 时间:2024/05/20 23:33


二叉树的遍历: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. 非递归的后序遍历中,栈中栈顶节点的下面的节点为栈顶节点的祖先节点,,即  将栈 中各个元素出栈可以得到栈顶节点到根结点的路径。



0 0