github:(
當年在學資料結構的時候,要求自己把**給實現一遍。在實現完線性表,棧和佇列之後,到了樹這章實現**確實有點難以入手,原因大家都懂,有遞迴。
樹的這章,比較重要的**是遞迴遍歷以及求深度,先弄明白這兩段**再去看關於樹的相關**就會容易很多。 這裡提個小小意見,遞迴很抽象,最好能畫個樹的圖,然後按照程式**在樹的圖中給畫出來,最好能debug一遍。
所以我給出這相關**。希望可以幫助大家。
#include typedef struct bitnode*bitree, bitnode;
void preorder(bitree t); //前序遍歷
void inorder(bitree t); //中序遍歷
void postorder(bitree t); //後序遍歷
void createbitree(bitree* t); //建立樹
int depth(bitree t);
int main()
void createbitree(bitree* t)
if (ch == '#')
else
}void preorder(bitree t)
}void inorder(bitree t)
}void postorder(bitree t)
}int depth(bitree t) else
else }}
這裡我建議你開啟兩個視窗來講下面的解釋和**一一對應來看。
line 1 匯入標頭檔案
line 3~6 二叉樹的資料結構,乙個資料域,兩個孩子結點的指標域
line 8~12 二叉樹的建立(根據先序遍歷序列),先序遍歷,中序遍歷,後序遍歷,求深度
line 14~29 在main函式對這些函式測試
line 31~48 根據先序遍歷序列進行建立樹,這個可以先不用看具體的實現。不過如果你像看的化,我還是簡單說下他是怎麼實現的。這個函式每次接收乙個字元,然後按照先序遍歷呼叫函式,根據字元(是資料還是空指標,空指標用』#'表示),如果是空指標就將傳進來的指標置為空,如果不是空指標,則建立乙個新的結點。
line 50~56 以先序遍歷的方式遍歷樹,先訪問根結點printf("%c ", t->data);
,再訪問左子樹preorder(t->lchild);
,右子樹preorder(t->lchild);
,這裡為什麼是左子樹右子樹,我想這就是遞迴的魅力了。 接下來我根據下面這張圖,對先序遍歷的過程(只對a結點及左子樹的,不然要寫太多了,你先看,記得對照圖看)做個說明。(圖中的灰色結點『#』平常不會畫出來,這裡我為了方便,才畫出來的)
其實遞迴呼叫會形成乙個遞迴圖,而這個遞迴圖就是一棵樹。所以你會發現先序遍歷是有且只會一次訪問結點(跟圖的不一樣,圖還要設乙個訪問陣列,來判斷當前結點是否被訪問過)。
上面這張圖,我把流向都給畫出來了,其中的數字代表第幾次被訪問。
首先我們會傳入根結點的指標到先序遍歷中(在main函式中呼叫的,line 18那裡),也是圖中的a結點,所以你看到圖中的1,那個代表是a結點是第乙個訪問。然後我們用printf("%c ", t->data);
把a結點的值給列印出來(算是a結點的訪問,你也可以用a結點做別的事,但是這裡為了舉例,用了列印來表示訪問)。
訪問完a結點後,preorder(t->lchild);
我們會執行這個語句,a函式因為沒執行完又去執行別的函式了,所以入函式棧裡,等它執行完的這個函式執行完畢後,a函式才會繼續執行剩下的preorder(t->rchild);
。
那我們可以看到a結點的左孩子是b,所以我們會訪問b,所以b是第2次訪問的結點(圖中標2)。
繼續,b結點訪問完,又呼叫了preorder(t->lchild);
,同樣的,b函式因為沒執行完又去執行別的函式了,所以入函式棧裡,我們現在棧裡有兩個函式,乙個是訪問a結點時的那個函式,乙個是b結點時的那個函式。
繼續,b結點的左孩子是空,我在圖中標記為#,t為空時,不滿足if (t != null)
所以,函式執行完畢,所以我們會出函式棧,把b給彈出來,然後把b繼續執行剛才未執行的語句。注意:這裡我在圖中把b的左孩子那個也寫了個數字3,說明我們是第三次訪問這個結點的,不過我們不做任何訪問的操作(把它列印出來)。
我們回到訪問b結點的那個函式,我們已經執行完preorder(t->lchild);
(就是上面那個步驟),程式會繼續執行preorder(t->rchild);
,這時b還沒有執行完畢,b壓入棧。這時棧有訪問a和b兩個結點的函式。
同樣的,跟b結點的左孩子一樣,不滿足if (t != null)
所以,函式執行完畢,所以我們會出函式棧,把訪問b的那個函式給彈出來,然後繼續執行剛才未執行完的**。這時函式棧就a了。
這時訪問的b結點的函式沒有其它語句了,b結點的函式執行完畢,出棧,這時出來的是訪問a的結點的函式,a結點剛才執行完preorder(t->lchild);
了,接下來會繼續訪問preorder(t->rchild);
,這是訪問a結點的函式入棧,訪問a的右結點c孩子…
不知道你看明白沒,我希望你自己能把**結合圖走一遍,你就能理解這個遞迴遍歷了。
line 58~64 以中序遍歷的方式遍歷樹,你會發現將上面先序遍歷訪問結點的那句**跟遞迴呼叫左孩子結點的那句**交換下順序就是中序遍歷**了
line 66~72 以後序遍歷的方式遍歷樹,同理,將上面先序遍歷訪問結點的那句**放在遞迴呼叫右孩子結點的那句**的後面即可
line 74~88 求樹的深度
求樹的深度,我建議你先看完遞迴遍歷,好好吸收一下遞迴的操作,然後根據**在圖里執行一遍。
求深度的思想主要在於返回。
line 75~76 在遇到空指標時,會直接返回0。看下圖的綠色部分。
line 78~79 在遇到非空指標時,會得到兩個子樹的深度,比如現在b結點的那個位置,他會得到左子樹的深度0(line 75~76遇到的空指標返回0),右子樹的深度0。
line 80~85 判斷兩者的哪個最大(因為depth=max,左右子樹的最大深度加上當前結點的深度(1))
以a結點來講,你看圖,a的左子樹深度為1,右子樹為2,那我們整棵樹是3=右子樹深度+1,返回給了main函式。
資料結構C語言二叉樹的遍歷
資料結構c語言二叉樹的遍歷 樹形結構是一類重要的非線性資料結構,其中以樹和二叉樹最為常用。二叉樹是每個結點最多有兩個子樹的有序樹。通常子樹的根被稱作 左子樹 left subtree 和 右子樹 right subtree 二叉樹常被用作二叉查詢樹和二叉堆或是二叉排序樹。二叉樹的每個結點至多只有二棵...
mysql 遍歷二叉樹 資料結構 二叉樹遍歷
這篇博文主要是研究二叉樹遍歷的遞迴與非遞迴演算法,有興趣的小夥伴可以了解下!二叉樹的遞迴遍歷 深度優先遍歷 先來張圖,看看各結點遍歷時的情況 二叉樹深度優先遍歷總結 分別為第一次,第二次,第三次進入某個結點 先序遍歷 先訪問根結點,然後先序遍歷左子樹,最後先序遍歷右子樹 根 左 右 中序遍歷 先中序...
資料結構 遍歷二叉樹
資料結構實驗之二叉樹二 遍歷二叉樹 time limit 1000ms memory limit 65536kb submit statistic problem description 已知二叉樹的乙個按先序遍歷輸入的字串行,如abc,de,g,f,其中,表示空結點 請建立二叉樹並按中序和後序的方...