1. 程式人生 > >資料結構入門---初始二叉樹(下)

資料結構入門---初始二叉樹(下)

這篇文章我們準備將二叉樹實現為具體的程式碼

首先我們要從二叉樹的遍歷說起。二叉樹的遍歷主要有四種形式

1. 前序遍歷
方法:如果二叉樹為空,則直接返回。如果二叉樹非空,則訪問根結點,再前序遍歷左子樹,然後前序遍歷右子樹
我們可以知道這樣的遍歷方式是以遞迴形式給出的。那麼我們以下面這棵樹為例,它的前序遍歷順序為: A B D G H C E F

這裡寫圖片描述

對於整個遍歷過程,首先從根結點開始。
1.訪問根結點A
2.訪問A的左子樹的根結點B(這樣描述是為了體現出遞迴,這裡進入了對左子樹的遞迴遍歷)
3.訪問B的左子樹的根結點D
4.訪問D的左子樹的根結點G
5.訪問G的左子樹的根結點,此時為空,什麼也不做,G的左子樹遍歷完畢。開始遍歷G的右子樹
6.訪問G的右子樹的根結點,為空,什麼也不做,這時D的左子樹遍歷完畢
7.向上返回至D,開始遞迴的前序遍歷D的右子樹,所以訪問結點H
8.H的左右子樹均為空。所以什麼也不做,向上返回(如步驟5,6)。這時以B為根的左子樹,也就是以D為根結點的樹遍歷完畢了
9.返回至B,遍歷B的右子樹,為空,返回。這時B為根節點的樹遍歷完畢,也就是A的左子樹遍歷完畢
10. 返回至A,開始遍歷A的右子樹。訪問A的右子樹根結點C。
11. 前序遍歷C的左子樹,訪問C的左子樹根結點E。
12. E左右子樹均為空,C的左子樹遍歷完畢,開始遍歷C的右子樹。於是訪問F
13. F左右子樹均為空,這時以A為根的右子樹遍歷完畢。
14. 整棵樹遍歷完畢

2.中序遍歷
方法:如果二叉樹為空,則直接返回。如果二叉樹非空,則從根結點開始中序遍歷左子樹,然後訪問根結點,然後中序遍歷右子樹
依舊以上圖的樹為例,其中序遍歷序列為: G D H B A E C F
具體的遍歷過程請參考上述前序的遍歷過程自行思考。關鍵點就是遍歷的順序以左子樹,根結點,右子樹,這樣的基本順序。自己心中模擬下遞迴的過程,便可理解

3.後序遍歷
方法:如果二叉樹為空,則直接返回。如果二叉樹非空,則從根結點開始,後序遍歷左子樹,然後後序遍歷右子樹,最後訪問根結點。
以上圖的樹為例,其後序遍歷序列為: G H D B E F C A
具體遍歷過程依舊請舉一反三的自己模擬遞迴過程理解,後序遍歷只要將處理順序改一下,現在我們需要先左,再右,最後才到根

現在我們將這三種遍歷實現為具體的程式碼

/*前序遍歷二叉樹*/
void BinTree::PreOrderTraversal(Node *&BT)
{
    if (BT)
    {
        //先訪問結點元素,再遞迴左右子樹
        Operation(BT->data);
        PreOrderTraversal(BT->lchild);  //遞迴遍歷左子樹
        PreOrderTraversal(BT->rchild);  //遞迴遍歷右子樹
    }
}
/*中序遍歷二叉樹*/
void BinTree::InOrderTraversal
(Node *&BT) { if (BT) { InOrderTraversal(BT->lchild); //遞迴遍歷左子樹 //訪問操作在兩遞迴間 Operation(BT->data); InOrderTraversal(BT->rchild); //遞迴遍歷右子樹 } }
/*後序遍歷二叉樹*/
void BinTree::PostOrderTraversal(Node *&BT)
{
    if (BT)
    {
        PostOrderTraversal(BT->lchild);     //遞迴遍歷左子樹
        PostOrderTraversal(BT->rchild);     //遞迴遍歷右子樹
        //兩個遞迴後再訪問結點資料
        Operation(BT->data);
    }
}

遞迴遍歷的程式碼很簡潔明瞭,基本就是複述了一遍遍歷規則。對於不同的遍歷方式,在程式碼上的區別就僅僅是對結點的訪問在程式碼中的位置。前序是在兩個遞迴之前,中序在兩個遞迴之間,後序則是兩個遞迴都結束之後才開始訪問根結點

層序遍歷
層序遍歷的方式與前三種遍歷有些不同,它是按層次逐層遍歷的
方法:若樹為空,則什麼也不做。如果樹不為空,則從樹的第一層起(根結點),從左至右遍歷同層結點,層次順序逐層向下。
那麼很顯然,對於上面的樹的層序遍歷序列為: A B C D E F G H

那麼我們要如何實現層序遍歷呢?層序遍歷,我們需要從根結點開始遍歷,從根結點開始訪問,當根結點訪問過之後,其左右孩子緊隨其後,如上圖A訪問過之後,緊接著輸出的就是A的左右孩子B,C。要實現這樣的一個接一個排隊著準備輸出的操作,我們就需要前面介紹過的資料結構–佇列了。
那麼下圖就是佇列變化以及輸出情況的整個流程

這裡寫圖片描述

我們先將根結點入隊,然後將根結點出隊並輸出,然後入隊根結點的左右孩子,如果沒有孩子就不入隊。然後不斷重複“取出隊頭元素,入隊隊頭元素的左右孩子”的操作。直到佇列為空時,遍歷完成。
在使用佇列之前你是不是在考慮二叉樹的同層之間的結點相互沒有指標相關聯,該如何做到按層的遍歷的呢?在使用了佇列之後是不是恍然大悟?我們只是通過上一層的結點來獲取下一層次的結點資訊。再通過佇列這樣特殊的線性結構儲存進去。記住這種處理方式,在未來學習圖的遍歷時還會用到這樣的思想。

那麼到現在二叉樹的幾種遍歷方式就介紹完了,但是現在問題出現了,我們連一個二叉樹都還沒有啊!下面我們就開始二叉樹的建立

為什麼要將遍歷放在前面介紹呢,其實這樣的順序會更有助你理解建立的方法首先先上程式碼

/*前序遍歷二叉樹*/
void BinTree::CreateBinTree(Node *&BT)
{
    char ch;
    cin >> ch;
    if (ch == '#')  //讀到 '#' 將結點設為空
        BT = NULL;
    else
    {
        BT = new Node;  //生成結點
        BT->data = ch;      //為結點賦值
        CreateBinTree(BT->lchild);      //建立左子樹
        CreateBinTree(BT->rchild);  //建立右子樹
    }
}

看了程式碼,我們是不是發現這個程式碼和前序遍歷的遞迴程式碼基本相同呢?沒錯,既然是遍歷操作,我們只要將訪問操作改成生成結點的建立操作不就好了?那麼對於遞迴終點,我們就需要一個無關字元來表明沒有左右孩子為空的情況,然後在讀到這個字元的時候將指標設為空。
所以對於前序建立,如果要建立之前圖中的那棵樹,就需要輸入序列:
A B D G # # H # # # C E # # F # #

相關推薦

資料結構入門---初始

這篇文章我們準備將二叉樹實現為具體的程式碼 首先我們要從二叉樹的遍歷說起。二叉樹的遍歷主要有四種形式 1. 前序遍歷 方法:如果二叉樹為空,則直接返回。如果二叉樹非空,則訪問根結點,再前序遍歷左子樹,然後前序遍歷右子樹 我們可以知道這樣的遍歷方式是以遞迴

資料結構作業11—選擇題

2-1要使一棵非空二叉樹的先序序列與中序序列相同,其所有非葉結點須滿足的條件是:(2分) A.結點的度均為2 B.只有右子樹 C.結點的度均為1 D.只有左子樹 作者: 考研試卷 單位: 浙江大學 2-2若一棵二叉樹的後序遍歷

郝斌資料結構入門--P67-的先序、中序、後序遍歷

郝斌資料結構入門--P67-二叉樹的先序、中序、後序遍歷   技巧:先、中、後序,是針對訪問根節點的位置來定義的。先序,先訪問根。中序,中間訪問根。後序,最後訪問根。   二叉樹的遍歷 (數是一個非線性的,通過先序、中序、後序遍歷把非線性的儲存線性的硬體上)

資料結構

上面兩篇我們瞭解了樹的基本概念以及二叉樹的遍歷演算法,還對二叉查詢樹進行了模擬實現。數學表示式求值是程式設計語言編譯中的一個基本問題,表示式求值是棧應用的一個典型案例,表示式分為字首、中綴和字尾三種形式。這裡,我們通過一個四則運算的應用場景,藉助二叉樹來幫助求解表

資料結構作業11—函式題

6-2 二叉樹求結點數 (15 分) 編寫函式計算二叉樹中的節點個數。二叉樹採用二叉連結串列儲存結構。 函式介面定義: int NodeCountOfBiTree ( BiTree T); 其中 T是二叉樹根節點的地址。 裁判測試程式樣例: //標頭檔案

資料結構作業11—判斷題

1-1若一個結點是某二叉樹的中序遍歷序列的最後一個結點,則它必是該樹的前序遍歷序列中的最後一個結點。 (2分) T F 作者: DS課程組 單位: 浙江大學 1-2若A和B都是一棵二叉樹的葉子結點,則存在這樣的二叉樹,其前序遍歷序列為…A…B

資料結構學習之面試易考題整理

【摘要】電腦科學中,二叉樹是每個節點最多有兩個子樹的樹結構。通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree)。二叉樹常被用於實現二叉查詢樹和二叉堆。二叉樹是遞迴定義的,因此,與二叉樹有關的題目基本都可以用遞迴思想解決

資料結構基礎溫故-4.

上面兩篇我們瞭解了樹的基本概念以及二叉樹的遍歷演算法,還對二叉查詢樹進行了模擬實現。數學表示式求值是程式設計語言編譯中的一個基本問題,表示式求值是棧應用的一個典型案例,表示式分為字首、中綴和字尾三種形式。這裡,我們通過一個四則運算的應用場景,藉助二叉樹來幫助求解表示式的值。首先,將表示式轉換為二叉樹,然後通過

資料結構入門--線索

當我們遍歷一棵二叉樹時,我們會得到整棵樹資料的一個序列(前or中or後),可以知道一個數據結點的前驅或者後繼是哪個結點。但是,對於每個結點的結構,我們只能從中得知某結點的左右孩子的資訊,要得到前驅/後繼結點的資訊就要遍歷一遍二叉樹,這樣豈不是很麻煩?我們能不能有

資料結構——程式碼

 二叉樹 C++ 環境codeblocks17 通過 /* 二叉樹 使用了自定義的 棧 和 佇列 @CGQ 2018/10/29 */ #include <iostream> #include <stdio.h> #include <stdlib.h&

資料結構——線索程式碼

線索二叉樹 C++ 環境codeblocks17 通過 /* 線索二叉樹 @CGQ 2018/10/29 */ #include <iostream> #include <stdio.h> #include <stdlib.h> using namesp

資料結構與演算法 -- 鏈式詳解/遞迴遍歷,葉子個數,深度計算

前言 PS:樹型結構是一種重要的非線性資料結構,教科書上一般都是樹與二叉樹,由此可見,樹和二叉樹是有區別和聯絡的,網上有人說二叉樹是樹的一種特殊形式,但經過查資料,樹和二叉樹沒有一個肯定的說法,但唯一可以肯定都是樹型結構。但是按照定義來看二叉樹並不是樹的一種特殊形式(下面解釋)。樹型資料結構的作

資料結構實驗之六:哈夫曼編碼SDUT 3345

題解:離散中的“最小生成樹(最優樹)”。 #include <bits/stdc++.h> using namespace std; void qusort(int l, int r, int a[]) { int x = a[l]; int i = l, j =

資料結構實驗之一:的同構 SDUT 3340

題解:把原本結構體的左右子樹的型別定義成 int 型,用來存放這個結點的左右子樹的編號,分別建造兩棵二叉樹,按個比較,如果在第二棵樹中沒有找到,那麼就不用在判斷了。 #include <bits/stdc++.h> using namespace std; struct node

資料結構實驗之八:中序後序的深度SDUT 2804

#include <stdio.h> #include <stdlib.h> #include <string.h> struct node { char data ; struct node *l,*r; }; struct node *cr

資料結構實驗之七:葉子問題SDUT 3346

#include <bits/stdc++.h> using namespace std; struct node { char data; struct node *lc, *rc; }; char a[100]; int num = 0; struct node

資料結構實驗之四:先序中序還原 SDUT 3343

#include <bits/stdc++.h> using namespace std; struct node { char data; struct node *lc, *rc; }; char a[100],b[100]; int n; struct node

資料結構實驗之五:層序遍歷 SDUT 3344

#include <bits/stdc++.h> using namespace std; struct node { char data; struct node *lc, *rc; }; char s[505]; int num; struct node *cre

資料結構實驗之三:統計葉子數有返回值版

Problem Description 已知二叉樹的一個按先序遍歷輸入的字元序列,如abc,de,g,f, (其中,表示空結點)。請建立二叉樹並求二叉樹的葉子結點個數。 Input 連續輸入多組資料,每組資料輸入一個長度小於50個字元的字串。 Output 輸出

資料結構實驗之四:先序中序還原

Problem Description 給定一棵二叉樹的先序遍歷序列和中序遍歷序列,要求計算該二叉樹的高度。 Input 輸入資料有多組,每組資料第一行輸入1個正整數N(1 <= N <=