數據結構--二叉樹的遍歷

遍歷的概念

順着某一條搜索路徑巡訪二叉樹中的結點,使得每個結點均被訪問一次,而且僅被訪問一次。

“訪問”的含義可以很廣,如:輸出結點的信息等。

“遍歷”是任何類型均有的操作,對線性結構而言,只有一條搜索路徑(因爲每個結點均只有一個後繼),故不需要另加討論。而二叉樹是非線性結構,每個結點有兩個後繼,則存在如何遍歷即按什麼樣的搜索路徑進行遍歷的問題

搜索路徑

對於“二叉樹”而言,可以有3條搜索路徑:

  1. 先上後下的按層次遍歷;
  2. 先左(子樹)後右(子樹)的遍歷;
  3. 先右(子樹)後左(子樹)的遍歷。

遍歷算法(非遞歸)

先序遍歷

若二叉樹爲空樹,則空操作;否則,

  1. 訪問根結點;
  2. 先序遍歷左子樹;
  3. 先序遍歷右子樹。

中序遍歷

若二叉樹爲空樹,則空操作;否則,

  1. 中序遍歷左子樹;
  2. 訪問根節點;
  3. 中序遍歷右子樹。

後序遍歷

若二叉樹爲空樹,則空操作;否則,

  1. 後序遍歷左子樹;
  2. 後序遍歷右子樹。
  3. 訪問根節點;

先序遍歷代碼描述

void preOrder(BiTree T, void(*visit)(int &e){
    //先序遍歷二叉樹
    if(T){
        visit(T->data); //訪問節點
        preOrder(T->lchild, visit); //遍歷左子樹
        preOrder(T->richild, visit);    //遍歷右子樹
    }
}

遍歷算法(遞歸)

中序遍歷

由中序遍歷過程可知,採用一個棧保存需要返回的結點指針,先掃描(並非訪問)根結點的所有左結點並將它們一一進棧。

然後出棧一個結點,顯然該結點沒有左孩子結點或者左孩子結點已訪問過,則訪問它。

然後掃描該結點的右孩子結點,將其進棧,再掃描該右孩子結點的所有左結點並一一進棧,如此這樣,直到棧空爲止。

void inOrder(BtTree root){
    initStack(&S);  //初始化棧
    p = root;
    while(p != NULL || !StackEmprt(S)){
        if(p != NULL){
            //根指針進棧,遍歷左子樹
            Push(&S, p);
            p = p->lchild;
        } else {
            //根指針出棧,訪問根節點,遍歷右子樹
            Pop(%S, p);
            Visit(p->data); //訪問節點
            p = p->rchild;
        }
    }
}

先序遍歷

由先序遍歷過程可知,先訪問根結點,再訪問左子樹,最後訪問右子樹。

因此,先將根結點進棧,在棧不空時循環:出棧p,訪問*p結點,將其右孩子結點進棧,再將左孩子結點進棧。

void preOrder(BtTree root){
    initStack(&S);
    p = root;
    if(root != NULL){
        Push(&S,p); //根節點進棧
        while(!StackEmpty(S)){  //棧不空時循環
            Pop(&S, p); //出棧並訪問該節點
            Visit(p->data);
            if(p->rchild != NULL){
                Push(&S,p)->rchild);    //右孩子進棧
            } else if(p->lchild != NULL){   //左孩子進棧
                Push(&S, lchild);
            }
        }
    }
}

由二叉樹的先序和中序序列建樹

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章