A. 什麼情況下可以利用遞歸來解決問題再寫遞歸程序時應注意是什麼
比如階乘,也就是說求n可以先求n-1,以此類推,到1,這類問題都可以用遞歸解決,菲波拉鍥數也可以遞歸。因為遞歸是總是調用自身解決問題,所以,必須有結束條件,否則會出問題,導致內存卡爆
「node.left!=null從根節點開始遞歸到9,跳出循環輸出9,接著判斷9的右節點為null;」
你這就話本身就有問題,輸出9時,那麼node是多少呢,是12,接著是判斷12的右節點,而不是9的右節點。
根節點是相對的,
你把9看成左節點,那麼12就是根節點,
按照中序遍歷規則,左中右,那麼輸出9就到12有什麼奇怪呢,
你把9看成根節點,它也是葉節點,沒有左右節點,那麼輸出9就到12有什麼奇怪呢。
你遞歸不懂就應該看譚浩強的遞歸分析,而不是來看二叉樹。
C. 1. 二叉樹是樹嗎它的定義為什麼是遞歸的 2. 三種根序遍歷主要思路是什麼 3
二叉樹(Binary tree)是一種演算法結構,是樹形結構的一種。因為存儲結構及其演算法都較為簡單,好理解,所以應用比較廣泛。二叉樹是n個有限元素的集合,該集合或者為空、或者由一個稱為根(root)的元素及兩個不相交的、被分別稱為左子樹和右子樹的二叉樹組成,是有序樹。當集合為空時,稱該二叉樹為空二叉樹。在二叉樹中,一個元素也稱作一個結點。
遞歸是演算法的一種,它是指一種通過重復將問題分解為同類的子問題而解決問題的方法。而二叉樹從演算法定義上看,或者是實際編程,3種遍歷方式,都符合遞歸演算法的特徵。
二叉樹遞歸遍歷分為先序遍歷、中序遍歷和後序遍歷。
先序遍歷為:根節點+左子樹+右子樹
中序遍歷為:左子樹+根節點+右子樹
後序遍歷為:左子樹+右子樹+根節點
(你只要記住根節點在哪裡就是什麼遍歷,且都是先左再右)
舉個例子,如二叉樹:
這棵樹的先序遍歷為:1 2 3 4 5
中序遍歷為:2 1 4 3 5
後序遍歷為:2 4 5 4 1
D. 先序遍歷二叉樹的遞歸演算法怎樣理解(嚴蔚敏主編)
先序調用的時候,遞歸函數,先序函數會一直遞歸,直到t->next為空,即t為葉節點,需要注意的是當t->next 為空時,函數的實參沒有傳過去,所以t指向葉結點的父節點,更要注意的是,先序調用的遞歸函數還沒執行完,在先序調用的最里層,要執行這個函數的最後一個語句,即先序訪問右子樹。
在了解遞歸函數時,要注意函數是一層一層執行的,把沒有調用的函數看作哦是第一層,第一次調用的時候,,勢必會第二次遇到調用函數,變成第二層,,,,
E. 二叉樹的遍歷演算法實現為何要採用遞歸
樹的結構定義本來就是遞歸思想!
F. 二叉樹先序遍歷遞歸演算法和非遞歸演算法本質區別
1. 先序遍歷
在先序遍歷中,對節點的訪問工作是在它的左右兒子被訪問之前進行的。換言之,先序遍歷訪問節點的順序是根節點-左兒子-右兒子。由於樹可以通過遞歸來定義,所以樹的常見操作用遞歸實現常常是方便清晰的。遞歸實現的代碼如下:
void PreOrderTraversal(BinTree BT)
{
if( BT )
{
printf(「%d\n」, BT->Data); //對節點做些訪問比如列印
PreOrderTraversal(BT->Left); //訪問左兒子
PreOrderTraversal(BT->Right); //訪問右兒子
}
}
由遞歸代碼可以看出,該遞歸為尾遞歸(尾遞歸即遞歸形式在函數末尾或者說在函數即將返回前)。尾遞歸的遞歸調用需要用棧存儲調用的信息,當數據規模較大時容易越出棧空間。雖然現在大部分的編譯器能夠自動去除尾遞歸,但是即使如此,我們不妨自己去除。非遞歸先序遍歷演算法基本思路:使用堆棧
a. 遇到一個節點,訪問它,然後把它壓棧,並去遍歷它的左子樹;
b. 當左子樹遍歷結束後,從棧頂彈出該節點並將其指向右兒子,繼續a步驟;
c. 當所有節點訪問完即最後訪問的樹節點為空且棧空時,停止。
實現代碼如下:
void PreOrderTraversal(BinTree BT)
{
BinTree T = BT;
Stack S = CreatStack(MAX_SIZE); //創建並初始化堆棧S
while(T || !IsEmpty(S))
{
while(T) //一直向左並將沿途節點訪問(列印)後壓入堆棧
{
printf("%d\n", T->Data);
Push(S, T);
T = T->Left;
}
if (!IsEmpty(S))
{
T = Pop(S); //節點彈出堆棧
T = T->Right; //轉向右子樹
}
}
}
由以上例子可以看出,遞歸與非遞歸的本質區別就是遞歸是不斷循環調用同一過程,非遞歸是循環執行同一個動作,並且非遞歸有入棧與出棧的過程,因此更節省存儲空間。個人淺見,歡迎指正。