喂,不是吧!一遍弄懂樹、圖的遍歷操作------入門級
話不多說,直接上教程!下面是本篇目錄。
前言:樹和圖都可以看作許多房間按照一定規則分佈,每一個房間可以看作一個結點(樹中稱為結點,圖中為頂點),小猿作為房東要訪問每個房間,也就是遍歷每個結點。無論房間如何分佈,小猿總會按照一定的路線依次訪問每個房間,也就是遍歷方式不同。
二叉樹的遍歷
前序遍歷(DLR)
- 遞迴演算法思想
若二叉樹為空則演算法結束;否則:
(1)訪問根結點;
(2)前序遍歷根結點的左子樹;
(3)前序遍歷根結點的右子樹。 - 通俗理解
如圖1是簡單的二叉樹,我們定義A是B、C的根房間,B是A的左房間,C是A的右房間。小猿每訪問一個房間之前,就要先訪問它的根房間,再依次訪問根房間的左房間、右房間。對於圖1的二叉樹,小猿依次訪問房間A、B、C。
- 解題思路
按照這個邏輯,小猿每訪問類似圖1這樣的簡單二叉樹都要遵循這個規則。對於圖2複雜的二叉樹,我們可以分析每個簡單二叉樹的訪問順序再彙總。表1為該二叉樹的子二叉樹及相應訪問順序。其中 A(_ B _ )( _ C _)表示確定ABC的訪問順序為ABC,但B、C及其左、右房間的訪問次序需要進一步確定。
子二叉樹 | 訪問順序 |
---|---|
A、B、C | A(_ B _ )( _ C _) |
B、D、E | B(_ D _ ) E |
D、G | DG |
C、F | C(_ F _ ) |
F、H | FH |
彙總後的前序遍歷 | ABDGECFH |
看到這裡是不是很神奇?,小猿終於通過前序遍歷把房間訪問完了,我們們繼續往下讀~
中序遍歷(LDR)
- 遞迴演算法思想
若二叉樹為空則演算法結束;否則:
(1)中序遍歷根結點的左子樹;
(2)訪問根結點;
(3)中序遍歷根結點的右子樹。 - 通俗理解
如圖3是簡單的二叉樹,我們定義A是B、C的根房間,B是A的左房間,C是A的右房間。小猿每訪問一個房間之前,就要先訪問它的左房間,再依次訪問這個房間(作為根房間)、右房間。對於圖1的二叉樹,小猿依次訪問房間B、A、C。
- 解題思路
按照這個邏輯,小猿每訪問類似圖3這樣的簡單二叉樹都要遵循這個規則。對於圖4複雜的二叉樹,我們可以分析每個簡單二叉樹的訪問順序再彙總。表2為該二叉樹的子二叉樹及相應訪問順序。其中 (_ B _ )A( _ C _)表示確定ABC的訪問順序為BAC,但B、C及其左、右房間的訪問次序需要進一步確定。
子二叉樹 | 訪問順序 |
---|---|
A、B、C | (_ B _ )A( _ C _) |
B、D、E | (_ D _ ) B E |
D、G | DG |
C、F | C (_ F _ ) |
F、H | HF |
彙總後的前序遍歷 | DGBEACHF |
小猿終於中序遍歷完了,我們們接著後序遍歷?~
後序遍歷(LRD)
- 遞迴演算法思想
若二叉樹為空則演算法結束;否則:
(1)後序遍歷根結點的左子樹;
(2)後序遍歷根結點的右子樹;
(3)訪問根結點。 - 通俗理解
如圖5是簡單的二叉樹,我們定義A是B、C的根房間,B是A的左房間,C是A的右房間。小猿每訪問一個房間之前,就要先依次訪問它的左、右房間,再訪問它(作為根房間)。對於圖5的二叉樹,小猿依次訪問房間B、C、A。
- 解題思路
按照這個邏輯,小猿每訪問類似圖5這樣的簡單二叉樹都要遵循這個規則。對於圖6複雜的二叉樹,我們可以分析每個簡單二叉樹的訪問順序再彙總。表2為該二叉樹的子二叉樹及相應訪問順序。其中 (_ B _ )( _ C _)A表示確定ABC的訪問順序為BCA,但B、C及其左、右房間的訪問次序需要進一步確定。
子二叉樹 | 訪問順序 |
---|---|
A、B、C | (_ B _ )( _ C _) A |
B、D、E | (_ D _ ) EB |
D、G | GD |
C、F | (_ F _ )C |
F、H | HF |
彙總後的前序遍歷 | GDEBHFCA |
小猿完成了後序遍歷,接下來的層序遍歷很簡單呦?
層序遍歷
- 遍歷演算法
(1)初始化設定一個佇列;
(2)把根結點指標入佇列;
(3)當佇列非空時,迴圈執行步驟(3.a)到步驟(3.c);
(3.a)出佇列取得一個結點指標,訪問該結點;
(3.b)若該結點的左子樹非空,則將該結點的左子樹指標入佇列;
(3.c)若該結點的右子樹非空,則將該結點的右子樹指標入佇列;
(4)結束。 - 通俗理解
按二叉樹的層序次序(即從根結點層至葉結點層),同一層中按先左子樹再右子樹的次序遍歷二叉樹。這個是二叉樹最好理解的遍歷方式了。圖7中二叉樹的層序遍歷為:ABCDEFGH。
在完成二叉樹遍歷的基礎上,樹的遍歷就不難啦?
樹的遍歷
先根遍歷
- 遞迴演算法思想
若樹為空則演算法結束;否則:
(1)訪問根結點;
(2)按照從左到右的次序先根遍歷根結點的每一棵子樹。 - 通俗理解
如圖8是簡單的樹,我們定義A是B、C、D的根房間,B、C、D是A的子房間。小猿每訪問一個房間之前,就要先訪問它的根房間,再按照從左到右的次序訪問根房間的子房間。對於圖8的樹,小猿依次訪問房間A、B、C、D。
- 解題思路
按照這個邏輯,小猿每訪問類似圖8這樣的簡單樹都要遵循這個規則。對於圖9複雜的樹,我們可以分析每個簡單的樹訪問順序再彙總。表3為該樹的子樹及相應訪問順序。其中 A (_ B _ )( _ C _)( _ D _)表示確定ABC的訪問順序為ABCD,但B、C、D及其子房間的訪問次序需要進一步確定。
子樹 | 訪問順序 |
---|---|
A、B、C、D | A (_ B _ )( _ C _)( _ D _) |
B、E、F、G | BE(_ F _ )G |
F、J | FJ |
C、H | C(_ H _ ) |
H、K、L | HKL |
D、I | DI |
彙總後的先根遍歷 | ABEFJGCHKLDI |
接下來後根遍歷,?
後根遍歷
- 遞迴演算法思想
若樹為空則演算法結束;否則:
(1)按照從左到右的次序後根遍歷根結點的每一棵子樹;
(2)訪問根結點。 - 通俗理解
如圖10是簡單的樹,我們定義A是B、C、D的根房間,B、C、D是A的子房間。小猿每訪問一個房間之前,就要先按照從左到右的次序訪問它的子房間,再訪問它(作為根房間)。對於圖10的樹,小猿依次訪問房間B、C、D、A。
- 解題思路
按照這個邏輯,小猿每訪問類似圖10這樣的簡單樹都要遵循這個規則。對於圖11複雜的樹,我們可以分析每個簡單的樹訪問順序再彙總。表4為該樹的子樹及相應訪問順序。其中 (_ B _ )( _ C _)( _ D _)A表示確定ABCD的訪問順序為BCDA,但B、C、D及其子房間的訪問次序需要進一步確定。
子樹 | 訪問順序 |
---|---|
A、B、C、D | (_ B _ )( _ C _)( _ D _) A |
B、E、F、G | E(_ F _ )GB |
F、J | JF |
C、H | (_ H _ )C |
H、K、L | KLH |
D、I | ID |
彙總後的後根遍歷 | EJFGEKLHCIDA |
當然,樹還有層序遍歷,類似於二叉樹的層序遍歷,這裡不再給出,接下來進入圖的遍歷,?
圖的遍歷
深度遍歷(連通圖)
- 遞迴演算法思想
若圖為空則演算法結束;否則:
(1)訪問頂點v並標記頂點v為已訪問;
(2)查詢頂點v的第一個鄰接頂點w;
(3)若頂點v的鄰接頂點w存在,則繼續執行,否則演算法結束;
(4)若頂點w尚未被訪問則深度優先搜尋遞迴訪問頂點w;
(5)查詢頂點v的w鄰接頂點的下一個鄰接頂點w,轉到步驟(3)。 - 通俗理解
圖的深度遍歷演算法類似於樹的先根遍歷,但是需要根據鄰接頂點的儲存次序訪問每個鄰接頂點。 - 無向連通圖
如圖12,式(1)(2)為其頂點集合和鄰接矩陣。我們從A頂點開始深度遍歷,遍歷的次序應為:ABCDE。其中遍歷到D頂點時,發現其沒有未訪問的鄰接頂點,則會回溯到B,訪問B的鄰接頂點E。這與樹的先根遍歷是類似的,樹的先根遍歷是先訪問根節點,再按照從左到右的次序訪問每棵子樹;圖的話是先訪問一個頂點,再按照其鄰接頂點的儲存次序訪問每個鄰接頂點。
V = [ A B C D E ] (1) V= \begin{bmatrix} A \\ B \\ C \\ D \\ E \\ \end{bmatrix} \tag{1} V=⎣⎢⎢⎢⎢⎡ABCDE⎦⎥⎥⎥⎥⎤(1)
E = [ 0 1 0 0 1 1 0 1 0 1 0 1 0 1 0 0 0 1 0 1 1 1 0 1 0 ] (2) E= \begin{bmatrix} 0 & 1 & 0 & 0 & 1\\ 1 & 0 & 1 & 0 & 1\\ 0 & 1 & 0 & 1 & 0\\ 0 & 0 & 1 & 0 & 1\\ 1 & 1 & 0 & 1 & 0 \end{bmatrix} \tag{2} E=⎣⎢⎢⎢⎢⎡0100110101010100010111010⎦⎥⎥⎥⎥⎤(2)
- 有向連通圖
有向連通圖與無向連通圖不同的是:
1, 有向連通圖邊是有方向的,如圖13,B鄰接到頂點是C,但C是沒有鄰接到任何頂點。
2, 無向連通圖、有向強連通圖從任一頂點出發都可以遍歷全圖,但有向連通圖不一定,如圖13為有向連通圖但非強連通圖,從頂點C是不能遍歷全圖的。
其中式(3)(4)為圖13的頂點集合和鄰接矩陣。我們從A頂點開始深度遍歷,遍歷的次序應為:ABCED。其中遍歷到D頂點時,發現其沒有鄰接到任何頂點,則會回溯到B,發現B也沒有鄰接到任何頂點,再回溯到A,發現A鄰接到頂點E,則訪問E,由於E鄰接到的B已訪問,下一個則會訪問頂點D。
V
=
[
A
B
C
D
E
]
(3)
V= \begin{bmatrix} A \\ B \\ C \\ D \\ E \\ \end{bmatrix} \tag{3}
V=⎣⎢⎢⎢⎢⎡ABCDE⎦⎥⎥⎥⎥⎤(3)
E
=
[
0
1
0
0
1
0
0
1
0
0
0
0
0
0
0
0
0
1
0
0
0
1
0
1
0
]
(4)
E= \begin{bmatrix} 0 & 1 & 0 & 0 & 1\\ 0 & 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 0 & 0\\ 0 & 0 & 1 & 0 & 0\\ 0 & 1 & 0 & 1 & 0 \end{bmatrix} \tag{4}
E=⎣⎢⎢⎢⎢⎡0000010001010100000110000⎦⎥⎥⎥⎥⎤(4)
廣度遍歷(連通圖)
- 遞迴演算法思想
若圖為空則演算法結束;否則:
(1)訪問初始頂點v並標記頂點v為已訪問;
(2)頂點v入佇列;
(3)當佇列非空時則繼續執行,否則演算法結束;
(4)出佇列取得隊頭頂點u;
(5)查詢頂點u的第一個鄰接頂點w;
(6)若頂點u的鄰接頂點w不存在,則轉到步驟(3),否則迴圈執行:
(6.1)若頂點w尚未被訪問則訪問頂點w並標記頂點w為已訪問;
(6.2)頂點w入佇列;
(6.3)查詢頂點u的w鄰接頂點後的下一個鄰接頂點w,轉到步驟(6)。 - 通俗理解
圖的廣度遍歷演算法類似於樹的層序遍歷,一層一層的遍歷,每一層再按照頂點的儲存次序訪問每個鄰接頂點。 - 無向連通圖
如圖14,式(5)(6)為其頂點集合和鄰接矩陣。我們從A頂點開始深度遍歷,可以把A、BE、C、D依次作為第一、二、三、四層,遍歷的次序應為:ABECD。
V = [ A B C D E ] (5) V= \begin{bmatrix} A \\ B \\ C \\ D \\ E \\ \end{bmatrix} \tag{5} V=⎣⎢⎢⎢⎢⎡ABCDE⎦⎥⎥⎥⎥⎤(5)
E = [ 0 1 0 0 1 1 0 1 0 1 0 1 0 1 0 0 0 1 0 1 1 1 0 1 0 ] (6) E= \begin{bmatrix} 0 & 1 & 0 & 0 & 1\\ 1 & 0 & 1 & 0 & 1\\ 0 & 1 & 0 & 1 & 0\\ 0 & 0 & 1 & 0 & 1\\ 1 & 1 & 0 & 1 & 0 \end{bmatrix} \tag{6} E=⎣⎢⎢⎢⎢⎡0100110101010100010111010⎦⎥⎥⎥⎥⎤(6)
- 有向連通圖
如圖15,式(7)(8)為其頂點集合和鄰接矩陣。我們從A頂點開始深度遍歷,可以把A、BE、CD依次作為第一、二、三層,遍歷的次序應為:ABECD。
V
=
[
A
B
C
D
E
]
(7)
V= \begin{bmatrix} A \\ B \\ C \\ D \\ E \\ \end{bmatrix} \tag{7}
V=⎣⎢⎢⎢⎢⎡ABCDE⎦⎥⎥⎥⎥⎤(7)
E
=
[
0
1
0
0
1
0
0
1
0
0
0
0
0
0
0
0
0
1
0
0
0
1
0
1
0
]
(8)
E= \begin{bmatrix} 0 & 1 & 0 & 0 & 1\\ 0 & 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 0 & 0\\ 0 & 0 & 1 & 0 & 0\\ 0 & 1 & 0 & 1 & 0 \end{bmatrix} \tag{8}
E=⎣⎢⎢⎢⎢⎡0000010001010100000110000⎦⎥⎥⎥⎥⎤(8)
非連通圖的遍歷
對於非連通圖,從圖的任意一個頂點開始深度或廣度優先遍歷並不能訪問圖中的所有頂點。只能訪問和初始頂點連通的所有頂點。但是,每一個頂點都作為一次初始頂點進行深度優先遍歷或廣度優先遍歷,並根據頂點的訪問標記來判斷是否需要訪問該頂點,就一定可以訪問非連通圖中的所有頂點,其中每個連通分量的遍歷方法與前面類似,這裡的話就不舉例了。
讀到結尾啦,小猿總結一下吧:樹其實是圖的一種特殊情況,二叉樹其實是樹的特殊情況,從圖到樹再到二叉樹,邊的數目減少,結點的儲存結構也更加簡單(從無序變得有序),相應的我們的遍歷方式也更加明確。到這裡小猿也累啦,留幾道思考題給大家吧?,答案在評論區
小猿初來乍到,希望大家多多支援!如有紕漏,歡迎大家在評論區留言,小猿會及時更正,同時,大家如果有疑惑的地方可以把問題寫在評論區,小猿看到會回覆喲?!
參考:
《資料結構——使用C語言(第五版)》 ------朱戰立
相關文章
- 一文弄懂二叉樹的三種遍歷方式二叉樹
- 整理了一系列的JavaScript樹操作方法,不用再一遍又一遍的百度了JavaScript
- 樹的遍歷方式
- 對二叉樹遍歷操作的深入思考二叉樹
- java實現二叉樹的Node節點定義手撕8種遍歷(一遍過)Java二叉樹
- 二叉樹的建立、前序遍歷、中序遍歷、後序遍歷二叉樹
- MySQL樹形遍歷MySql
- 二叉樹的廣度遍歷和深度遍歷()二叉樹
- Javascript樹(一):廣度遍歷和深度遍歷JavaScript
- 樹的遍歷c/c++C++
- 二叉樹的遍歷二叉樹
- 二叉樹建立,前序遍歷,中序遍歷,後序遍歷 思路二叉樹
- 玩轉二叉樹(樹的遍歷)二叉樹
- 入門級的Git操作Git
- 二叉樹---遍歷二叉樹
- 二叉樹遍歷二叉樹
- MySQL樹形遍歷(三)MySql
- 二叉樹的遍歷 → 不用遞迴,還能遍歷嗎二叉樹遞迴
- 完全二叉樹的遍歷二叉樹
- MySQL 實現樹形的遍歷MySql
- 圖的遍歷演算法-馬遍歷棋盤演算法
- C++樹——遍歷二叉樹C++二叉樹
- 144.二叉樹的前序遍歷145.二叉樹的後序遍歷 94.二叉樹的中序遍歷二叉樹
- 演算法競賽——樹和圖的儲存與遍歷演算法
- 面試中很值得聊的二叉樹遍歷方法——Morris遍歷面試二叉樹
- LintCode 前序遍歷和中序遍歷樹構造二叉樹二叉樹
- 二叉樹遍歷方法二叉樹
- 二叉樹遍歷 -- JAVA二叉樹Java
- 掌握 React 元件樹遍歷技巧React元件
- JAVA遍歷二叉樹Java二叉樹
- 根據二叉樹的前序遍歷和中序遍歷輸出二叉樹;二叉樹
- 建立二叉樹:層次遍歷--樹的寬度高度,後序遍歷--祖先節點二叉樹
- 二叉樹的遍歷實現二叉樹
- 二叉樹的遍歷筆記二叉樹筆記
- 二叉樹的層序遍歷二叉樹
- 二叉樹的按層遍歷二叉樹
- 【練習】二叉樹的遍歷二叉樹
- 二叉樹的建立與遍歷二叉樹