7 7 線索二叉樹

2021-08-13 21:42:52 字數 2066 閱讀 3263

對於普通含有

n 個結點的二叉樹來說,一共含有2n

個指標域,而實際上,樹的頂點集中元素的個數

v 和邊集中元素的個數

e的關係滿足|v

|=|e

|+1 ,也就是說在上述二叉樹中n=

e+1 ,得e=

n−1 ,共n−

1 條邊,於是只需要n−

1 個指標就可以刻畫這顆二叉樹了。但是在採用二叉鏈儲存結構的二叉樹來說,對於大多數語言來說,宣告乙個二叉樹結點,必須靜態指定兩個指標域,分別表示左孩子和右孩子,這樣必然會浪費掉n+

1 個指標,他們指向空,就等於說是完全浪費了。

因此採用線索二叉樹,就是在於充分利用這些空餘的指標,來提高一種樹的常用操作——遍歷的效率。不過實際上,往往並不會刻意去構造一顆線索二叉樹,在最後會作分析。

考慮到二叉樹的遍歷結果是乙個線性序列,因此,很自然地需要乙個東西用來表示前驅和後繼的關係。

因此定義:線索(thread)是指向當前結點的「前驅」或者「後繼」的指標。建立線索的過程稱之為線索化。

為了區分乙個結點上的指標到底是線索還是實際的孩子,我們需要使用乙個輔助標記tag_is_thread,如果為真則為線索,反之指向孩子的指標。在實際實現的過程中,往往還需要乙個頭結點(啞元),指向樹根。

因為線索確實不是很常見,因此沒有實現具體的**,基本上是參考書上的**,故此處**從略。

建立線索實際上就是在一棵已經構造好了的二叉樹上遍歷,在遍歷過程中新增線索。線索實際上是乙個將樹扁平化的過程,因此每一步新增線索的關鍵在於,要找到前驅pre。這樣cur的前驅就是pre,而pre的後繼就是cur。至於處理的位置,就是遍歷過程中應該訪問的位置。比如中序遍歷,就要在訪問左子樹和右子樹中間進行處理,這樣線索就維持了中序遍歷的前後關係。

特殊地方的處理在於啞元結點。啞元結點指向樹根,而整個遞迴過程結束時,pre恰好指向最後乙個結點。因此pre的後繼就是啞元,而啞元的前驅就是pre了。

為了遞迴過程中pre的可用性,pre是全域性變數。

實際上,利用線索,將二叉樹遍歷過程也轉化成了乙個雙向迴圈鍊錶。

使用線索就更為簡單了。首先需要借助開始的啞元結點找到序列的第乙個元素,然後一直找右孩子結點。如果是線索,直接挪向這個線索指向的結點;如果不是線索,就去找左孩子。直到回到開始的啞元結點,整個遍歷結束。

首先,較為簡單的,也就是書上提到的建立線索的演算法,是對於靜態集合而言。對於動態插入和刪除的樹(平衡搜尋樹),其在集合發生變化時,維持線索的複雜程度要高得多。

為什麼stl和linux都使用紅黑樹作為平衡樹的實現? - 雷鵬的回答 - 知乎

這個回答確實提出,使用線索時,正向遍歷效率很高,但是其實現是非常依賴技巧的。它將一棵紅黑樹的兩個結點用陣列表示,ltagrtag標記位用1位二進位制分別並在lchildrchild的31位後面,也就是說childtag一共才占用乙個機器字長。而如果使用二叉鏈的指標式表示,這是不可能的:指標必須占用乙個機器字長,才能對整個位址空間進行定址。另外再用乙個tag,由於記憶體對齊原因,還要再占用乙個機器字長。不同於資料結構課程中理想化考慮tag用作bool布林型只需要乙個二進位制位,實際上由於記憶體對齊的原因,這樣反而額外浪費了一倍的空間(arm架構要求指令必須對齊,而x86雖然可以不對齊,但是取指令就需要兩次週期,效率顯而易見。)

況且,對於二叉樹遍歷來說,一旦「碰底」,也就是當前子樹處理完畢進行回溯,以中序遍歷為例,有左孩子的非葉子結點需要被訪問兩次(想想非遞迴,先進棧後出棧),因此,額外增加的時間開銷也最多根沒有左孩子的非葉子結點個數成正比,最壞的情況不過o(

n),並不會增加漸進複雜度。

該回答中線索提高的效率,屬於常數優化,並且和順序結構代替鏈式結構,有效地利用了儲存器的空間區域性性也極大地提高了效率。

線索二叉樹

當用二叉鍊錶作為二叉樹的儲存結構時,因為每個結點中只有指向其左 右兒子結點的指標,所以從任一結點出發只能直接找到該結點的左 右兒子。在一般情況下靠它無法直接找到該結點在某種遍歷序下的前驅和後繼結點。如果在每個結點中增加指向其前驅和後繼結點的指標,將降低儲存空間的效率。我們可以證明 在n個結點的二叉鍊...

線索二叉樹

1.線索二叉樹結構和操作定義 threadbintree.h 功能 線索標誌域所有值 typedef enumnodeflag 功能 線索二叉樹結構體 typedef struct threadtreethreadbintree 前驅節點指標 threadbintree previous null ...

線索二叉樹

原始碼 中序線索二叉樹 author 菜鳥 version 2014.7.23 include include include typedef char datatype using namespace std 定義線索二叉樹的結構體 typedef struct nodethreadbitreen...