二叉樹的遍歷

1、二叉樹的遍歷

1.1 先序遍歷

遍歷過程爲:python

  1. 訪問根結點
  2. 先序遍歷其左子樹;
  3. 先序遍歷其右子樹。
/* c語言實現 */

// 定義結點
typedef struct TreeNode *BinTree;
typedef BinTree Position;
struct TreeNode{
  ElementType Data;
  BinTree Left;
  BinTree Right;
}

void PreOrderTraversal (BinTree BT)
{
  if (BT) {
    printf("%d", BT->Data);
    PreOrderTraversal(BT->Left);
    PreOrderTraversal(BT->Right);
  }
}
# python語言實現

# 定義結點
class TreeNode:
     def __init__(self, x):
         self.val = x
         self.left = None
         self.right = None
        
def preorder(root):
    if not root:
        return 
    print(root.val)
    preorder(root.left)
    preorder(root.right)

先序遍歷:A (B D F E)(C G H I)算法

1.2 中序遍歷

遍歷過程爲:app

  1. 中序遍歷其左子樹
  2. 訪問根節點
  3. 中序遍歷其右子樹
/* c語言實現 */

void InOrderTraversal (BinTree BT)
{
  if (BT) {
    InOrderTraversal(BT->Left);
    printf("%d", BT->Data);
    InOrderTracersal(BT->Right);
  }
}
# python語言實現

def inorder(root):
    if not root:
        return 
    inorder(root.left)
    print(root.val)
    inorder(root.right)

中序遍歷:(D B E F)A(G H C I)函數

1.3 後序遍歷

遍歷過程爲:post

  1. 後序遍歷其左子樹
  2. 後序遍歷其右子樹
  3. 訪問根結點
/* c語言實現 */

void PostOrderTraversal (BinTree BT)
{
  if (BT) {
    PostOrderTraversal(BT->Left);
    PostORderTraversal(BT->Right);
    printf("%d", BT->Data);
  }
}
# python語言實現

def postorder(root):
    if not root:
        return 
    postorder(root.left)
    postorder(root.right)
    print(root.val)

後序遍歷:(D E F B)(H G I C)Aspa

1.4 小結

先序、中序和後序遍歷過程:遍歷過程當中通過結點的路線同樣,只是訪問各結點的時機不一樣指針

圖中在從入口到出口的曲線上用×、☆、△三種符號分別標記出了先序、中序和後序訪問各結點的時刻。code

2、二叉樹的非遞歸遍歷

非遞歸算法實現的基本思路:使用堆棧對象

2.1 中序遍歷非遞歸遍歷算法

  1. 遇到一個結點,就把它壓棧,並去遍歷它的左子樹
  2. 左子樹遍歷結束後,從棧頂彈出這個結點並訪問它
  3. 而後按其右指針再去中序遍歷該結點的右子樹
/* c語言實現 */

void InOrderTraversal(BinTree BT)
{
  BinTree T = BT;
  Stack S = CreateStack(MaxSize); // 建立並初始化堆棧S
  while (T || !IsEmpty(S)){
    while (T) { // 一直向左並將沿途結點壓入堆棧
        Push(S, T);
      T = T->Left;
    }
    if (!IsEmpty(S)){
      T = Pop(S); // 結點彈出堆棧
      printf("%5d", T->Data); // (訪問)打印結點
      T = T->Right; // 轉向右子樹
    }
  }
}
# python語言實現
def inorder(root):
    stack = []
    while stack or root:
        while root:
            stack.append(root)
            root = root.left
        root = stack.pop()
        print(root.val)
        root = root.right

2.2 先序遍歷的非遞歸遍歷算法

/* c語言實現 */

void InOrderTraversal(BinTree BT)
{
  BinTree T = BT;
  Stack S = CreateStack(MaxSize); // 建立並初始化堆棧S
  while (T || !IsEmpty(s)){
    while (T) { // 一直向左並將沿途結點壓入堆棧
        printf("%5d", T->Data); // (訪問)打印結點
      Push(S, T);
      T = T->Left;
    }
    if (!IsEmpty(S)){
      T = Pop(S); // 結點彈出堆棧
      T = T->Right; // 轉向右子樹
    }
  }
}
# python語言實現

def preorder(root):
    stack = [root]
    while stack:
        s = stack.pop()
        if s:
            print(s.val)
            stack.append(s.right)
            stack.append(s.left)

2.3 後序遍歷的非遞歸遍歷算法

// c語言實現

// 定義結點
typedef struct TreeNode{
    int data;
    struct TreeNode *lChild;
    struct TreeNode *rChild;
} TreeNode;

void postOrder(TreeNode *T){
    TreeNode *stack[15];
    int top = -1;
    int flagStack[15];   //記錄每一個節點訪問次數棧
    TreeNode *p = T;
    while(p!=NULL||top!=-1){
        if(p!=NULL){     //第一次訪問,flag置1,入棧
            stack[++ top] = p;
            flagStack[top] = 1;   
            p = p->lChild;
        }else{//(p == NULL)
            if(flagStack[top] == 1){  //第二次訪問,flag置2,取棧頂元素但不出棧
                p = stack[top];
                flagStack[top] = 2;
                p = p->rChild;
            }else{         //第三次訪問,出棧
                p = stack[top --];
                printf("%d\t",p->data);    //出棧時,訪問輸出
                p = NULL;      //p置空,以便繼續退棧
            }
        }
    }
# python語言實現

def postorder(root):
    stack = []
    while stack or root:
        while root:                 # 下行循環,直到找到第一個葉子節點

            stack.append(root)
            if root.left:           # 能左就左,不能左就右

                root = root.left 
            else:
                root = root.right     
        s = stack.pop()
        print(s.val)
        #若是當前節點是上一節點的左子節點,則遍歷右子節點

        if stack and s == stack[-1].left: 

            root = stack[-1].right
        else:
            root = None

3、層序遍歷

二叉樹遍歷的核心問題:二維結構的線性化。即從結點訪問其左、右兒子結點,訪問左兒子後,若是根結點信息丟失,右兒子結點也會隨之丟失,所以須要一個存儲結構保存暫時不訪問的結點,這個存儲結構能夠爲堆棧,也能夠是隊列。

3.1 隊列實現

遍歷從根節點開始,首先將根節點入隊,而後開始執行循環:結點出隊、訪問該結點、其左右兒子入隊。

層序基本過程:先根結點入隊,而後:

  1. 從隊列中取出一個元素;
  2. 訪問該元素所指結點;
  3. 若該元素所指結點的左、右孩子結點非空,則將其左、右孩子的指針順序入隊
/* c語言實現 */

void LevelOrderTraversal (BinTree BT)
{
  Queue Q; BinTree T;
  if (!BT) return; // 如果空樹則直接返回
  Q = CreateQueue(MaxSize); // 建立並初始化隊列Q
  AddQ(Q, BT);
  while (!IsEmptyQ(Q))
  {
    T = DeleteQ(Q);
        printf("%d\n", T->Data); // 訪問取出隊列的結點
    if (T->Left) AddQ(Q, T->Left);
    if (T->Right) AddQ(Q, T->Right);
  }
}
# python語言實現

def BFS(root):
    queue = [root]
    while queue:
        n = len(queue)
        for i in range(n):
            q = queue.pop(0)
            if q:
                print(q.val)
                queue.append(q.left if q.left else None)
                queue.append(q.right if q.right else None)

4、實際應用

4.1 遍歷二叉樹的應用:輸出二叉樹中的葉子節點

在二叉樹的遍歷算法中檢測結點的左右子樹是否都爲空

/* c語言實現 */

void PreOrderPrintLeaves (BinTree BT)
{
  if (BT) {
    if (!BT->Left && !BT->Right)
      printf("%d", BT->Data);
    PreOrderPrintLeaves(BT->Left);
    PreOrderPrintLeaves(BT->Right);
  }
}
# python語言實現

class Node(object):
    """節點類"""

    def __init__(self, val=-1, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


class Tree(object):
    """樹類"""

    def __init__(self):
        self.root = Node()
        self.queue = []  # 使用列表模擬隊列

    def add(self, val):
        """爲樹添加節點"""
        node = Node(val)

        if self.root.val == -1:  # 若是樹是空的,則對根節點賦值

            self.root = node
            self.queue.append(self.root)
        else:
            treeNode = self.queue[0]  # 此結點的子樹尚未齊。
            if treeNode.left == None:
                treeNode.left = node  # 左子樹變成節點(初始此節點左右都是None)
                self.queue.append(treeNode.left)
            else:
                treeNode.right = node
                self.queue.append(treeNode.right)
                self.queue.pop(0)  # 若是該結點存在右子樹,將此結點丟棄。

    def leave(self, root):
        if root == None:
            return 0
        elif root.left == None and root.right == None:
            return 1
        else:
            return (self.leave(root.left) + self.leave(root.right))  # 遞歸遍歷全部左子樹右子樹,當左右都爲None時纔算1


if __name__ == '__main__':
    """主函數"""
    vals = range(10)  # 生成十個數據做爲樹節點
    tree = Tree()  # 新建一個樹對象
    for val in vals:
        tree.add(val)  # 逐個添加樹的節點
    print('葉子節點個數:', tree.leave(tree.root))

4.2 求二叉樹的高度

/* c語言實現 */

int PostOrderGetHeight(BinTree BT)
{
  int HL, HR, MaxH;
  if (BT) {
    HL = PostOrderGetHeight(BT->Left); // 求左子樹的深度
    HR = PostOrderGetHeight(BT->Right); // 求右子樹的深度
    MaxH = (HL > HR) ? HL : HR; // 取左右子樹較大的深度
    return (MaxH + 1); // 返回樹的深度
  }
  else return 0; // 空樹深度爲0
}
# python實現

# 基本思路就是遞歸,當前樹的最大深度等於(1+max(左子樹最大深度,右子樹最大深度))。

def maxDepth(root):

    if not root:
        return 0
    return 1+max(maxDepth(root.left), maxDepth(root.right))

4.3 二元運算表達式樹及其遍歷

三種遍歷能夠獲得三種不一樣的訪問結果:

  • 先序遍歷獲得前綴表達式:++a*bc*+*defg
  • 中序遍歷獲得中綴表達式(中綴表達式會受到運算符優先級的影響):a+b*c+d*e+f*g
  • 後序遍歷獲得後綴表達式:abc*+de*f+g*+

4.4 由兩種遍歷序列肯定二叉樹

已知三種遍歷中的任意兩種遍歷序列,不能惟一肯定一顆二叉樹,若是兩種遍歷序列中有中序遍歷,則能夠惟一肯定一顆二叉樹。

對於給出的先序遍歷序列爲:AB後序遍歷序列:BA,可能有以下兩種狀況:

先序和中序遍歷序列來肯定一顆二叉樹

  • 根據先序遍歷序列第一個結點肯定根節點
  • 根據根節點在中序遍歷序列中分割出左右兩個子序列
  • 左子樹和右子樹分別遞歸使用相同的方法繼續分解

相似地,後序和中序遍歷序列也能夠肯定一顆二叉樹。

相關文章
相關標籤/搜索