遍歷二叉樹,是學習樹這種數據結構首先要理解的一種基本操作。比較簡單地方式就是用遞歸去遍歷,鑑於遞歸這種調用方法有一定的特殊性,今天還是想來講講怎麼去理解遞歸遍歷。本文針對想理解遞歸的過程的朋友,因爲本人在學到這一部分的時候也糾結了很久,其實只要理解了過程,那以後寫遞歸的代碼再也不用“心虛”了,因爲那個過程是可預測的,可證明的。
遞歸調用的特殊性在於自己調用自己,給人一種迷茫感,如果是遞歸調用“一次”,那還相對好理解,比如求階乘的遞歸算法,
- int F(int n)
- {
- if(n==0)//遞歸邊界
- return 1;
- return n*F(n-1);//遞歸公式
- }
一層一層調用,知道遞歸結束條件成立,再一層一層返回;但如果像二叉樹是遞歸調用“兩次”,似乎理解起來就不是很容易了。
- void preorder(bintree t){
- if(t){
- printf("%c ",t->data);
- preorder(t->lchild);
- preorder(t->rchild);
- }
- }
對於一顆如下的二叉樹,它的前序遍歷順序該怎麼理解呢?我們今天來好好理一遍它的過程。
可以把遞歸看成是自己調用另一個和自己功能一樣,但是函數名不同的函數來理解,或許看得更清楚明白,下面我們來看看這個前序遍歷的過程是怎樣的。
首先,我們記上面這個函數爲F1,表示外層的函數,內層函數表示下一層的函數,也就是第二層的F2,依次類推。
那從F1依次調用直到F3,注意這個時候都是在左子樹就是L的調用,所以依次打印出“A B D ”,這都沒什麼問題,就是普通函數調用。F3調用F4的時候,記得我們層函數的最前面是遞歸的退出條件,也就是空子樹就返回,由於D的左子樹是空,所以到這裏F4會返回到F3,即返回到L之後,R之前。
接在,在F3層,從R開始繼續調用F4,即開始訪問D的右子樹,此時打印出“F”,然後調用F4的左子樹,也就是調用F5函數,當然是空,所以返回到F4,再調用F4的右子樹,也是空,所以也是返回到F4,此時F4這一層已經全部調用完成,所以繼續向上返回到F3,記得我們之前是怎麼下來的嗎,就是從F3的右子樹開始訪問,所以F3層函數也已經調用完成,繼續往上返回到F2。
繼續調用F2的右子樹,也就是調用F3函數,此時打印出“E”,接着再訪問E的左右子樹,都是空,所以返回到F2,F2層函數已經全部調用完成。返回到F1,也就是A的左子樹部分全部訪問完成,此時開始訪問A的右子樹,打印出“C”,再推下去就是依次打印“G”和“H”。至此,整顆二叉樹節點前序遍歷完成,順序就是“A B D F E C G H”。
二叉樹是一種遞歸定義的數據結構,所以用遞歸來寫它的相關算法是順理成章的,只是有時候覺得需要稍微理解一下這個過程,這個就是我的理解方法。