【程序人生】數據結構雜記(四)

說在前面

個人讀書筆記

二叉樹

樹屬於半線性結構——附加某種約束(比如遍歷),也可以在樹中的元素之間確定某種線性次序
樹是一種分層結構

TT中所有節點深度的最大值稱作該樹的高度(height)(height),記作height(T)height(T)

不難理解,樹的高度總是由其中某一葉節點的深度確定的。特別地,僅含單個節點的樹高度爲00,空樹高度爲1-1
推而廣之,任一節點vv所對應子樹subtree(v)subtree(v)的高度,亦稱作該節點的高度,記作height(v)height(v)。特別地,全樹的高度亦即其根節點rr的高度,height(T)=height(r)height(T) = height(r)

二叉樹的實現

作爲圖的特殊形式,二叉樹的基本組成單元是節點與邊;作爲數據結構,其基本的組成實體是二叉樹節點(binary tree node),而邊則對應於節點之間的相互引用。

遍歷

二叉樹本身並不具有天然的全局次序,故爲實現遍歷,需通過在各節點與其孩子之間約定某種局部次序,間接地定義某種全局次序。
按慣例左兄弟優先於右兄弟,故若將節點及其孩子分別記作V、L和R,則如下圖所示,局部訪問的次序可有VLR、LVR和LRV三種選擇。根據節點V在其中的訪問次序,三種策略也相應地分別稱作先序遍歷、中序遍歷和後序遍歷
在這裏插入圖片描述

先序遍歷

在這裏插入圖片描述爲遍歷(子)樹xx,首先覈對xx是否爲空。若xx爲空,則直接退出——其效果相當於遞歸基。
反之,若xx非空,則按照先序遍歷關於局部次序的定義,優先訪問其根節點xx;然後,依次深入左子樹和右子樹,遞歸地進行遍歷。
在這裏插入圖片描述

迭代實現先序遍歷

在這裏插入圖片描述
在二叉樹TT中,從根節點出發沿着左分支一直下行的那條通路(以粗線示意),稱作最左側通路(leftmost path)。若將沿途節點分別記作LkL_kk=0,1,2,...,dk = 0, 1, 2, ..., d,則最左側通路終止於沒有左孩子末端節點LdL_d。若這些節點的右孩子和右子樹分別記作RkR_kTkT_kk=0,1,2,...,dk = 0, 1, 2, ..., d,則該二叉樹的先序遍歷序列可表示爲:
在這裏插入圖片描述
也就是說,先序遍歷序列可分解爲兩段:
沿最左側通路自頂而下訪問的各節點,以及自底而上遍歷的對應右子樹。
基於對先序遍歷序列的這一理解,可以導出以下迭代式先序遍歷算法。
在這裏插入圖片描述在這裏插入圖片描述在全樹以及其中每一棵子樹的根節點處,該算法都首先調用函數VisitAlongLeftBranch(),自頂而下訪問最左側通路沿途的各個節點。這裏也使用了一個輔助棧,逆序記錄最左側通路上的節點,以便確定其對應右子樹自底而上的遍歷次序。

中序遍歷

在這裏插入圖片描述各節點在中序遍歷序列中的局部次序,與按照有序樹定義所確定的全局左、右次序完全吻合

迭代版中序遍歷

在這裏插入圖片描述參照迭代式先序遍歷的思路,再次考查二叉樹TT的最左側通路,並對其中的節點和子樹標記命名。於是,TT的中序遍歷序列可表示爲:
在這裏插入圖片描述
在這裏插入圖片描述
在全樹及其中每一棵子樹的根節點處,該算法首先調用函數goAlongLeftBranch(),沿最左側通路自頂而下抵達末端節點LdL_d 。在此過程中,利用輔助棧逆序地記錄和保存沿途經過的各個節點,以便確定自底而上各段遍歷子序列最終在宏觀上的拼接次序。
在這裏插入圖片描述

中序遍歷序列直接後繼及其定位

這裏,共分兩大類情況。
若當前節點有右孩子,則其直接後繼必然存在,且屬於其右子樹。此時只需轉入右子樹,再沿該子樹的最左側通路朝左下方深入,直到抵達子樹中最靠左(最小)的節點。
反之,若當前節點沒有右子樹,則若其直接後繼存在,必爲該節點的某一祖先,且是將當前節點納入其左子樹的最低祖先。於是首先沿右側通路朝左上方上升,當不能繼續前進時,再朝右上方移動一步即可。
作爲後一情況的特例,出口時s可能爲NULL。這意味着此前沿着右側通路向上的回溯,抵達了樹根。也就是說,當前節點全樹右側通路的終點——它也是中序遍歷的終點,沒有後繼。
在這裏插入圖片描述

迭代版中序遍歷(無需輔助棧)

在這裏插入圖片描述可見,這裏相當於將原輔助棧替換爲一個標誌位backtrack。每當抵達一個節點,藉助該標誌即可判斷此前是否剛做過一次自下而上的回溯。若不是,則按照中序遍歷的策略優先遍歷左子樹。反之,若剛發生過一次回溯,則意味着當前節點的左子樹已經遍歷完畢(或等效地,左子樹爲空),於是便可訪問當前節點,然後再深入其右子樹繼續遍歷。
每個節點被訪問之後,都應轉向其在遍歷序列中的直接後繼。按照以上的分析,通過檢查右子樹是否爲空,即可在兩種情況間做出判斷:
該後繼要麼在當前節點的右子樹(若該子樹非空)中,要麼(當右子樹爲空時)是其某一祖先。後一情況即所謂的回溯。請注意,由succ()返回的直接後繼可能是NULL,此時意味着已經遍歷至中序遍歷意義下的末節點,於是遍歷即告完成。

後序遍歷

在這裏插入圖片描述
先序遍歷序列與後序遍歷序列並非簡單的逆序關係

層次遍歷

在所謂廣度優先遍歷或層次遍歷(level-order traversal)中,確定節點訪問次序的原則可概括爲“先上後下、先左後右”——先訪問樹根,再依次是左孩子、右孩子、左孩子的左孩子、左孩子的右孩子、右孩子的左孩子、右孩子的右孩子、…,依此類推。

當然,有根性和有序性是層次遍歷序列得以明確定義的基礎。正因爲確定了樹根,各節點方可擁有深度這一指標,並進而依此排序;有序性則保證孩子有左、右之別,並依此確定同深度節點之間的次序。
在這裏插入圖片描述此前介紹的迭代式遍歷,無論先序、中序還是後序遍歷,大多使用了輔助棧,而迭代式層次遍歷則需要使用與棧對稱的隊列結構
在這裏插入圖片描述
示例:
在這裏插入圖片描述

完全二叉樹

葉節點只能出現在最底部的兩層,且最底層葉節點均處於次底層葉節點的左側

滿二叉樹

所有葉節點同處於最底層

結語

如果您有修改意見或問題,歡迎留言或者通過郵箱和我聯繫。
手打很辛苦,如果我的文章對您有幫助,轉載請註明出處。

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