介紹常規的三種遞迴遍歷方法(先中後)以及非遞迴的先序、中序、後序、層序遍歷
對二叉樹這種資料結構有一定了解
遍歷二叉樹的目的是為了訪問到每個結點且按照某一特定的順序
一定要記住子樹的根->左->右
遞迴的特點就是**可讀性高,容易理解
/*先序遍歷,以rt為根的樹*/ //根->左->右
template void binarytree::preorder(const node* rt, void(*visit)(const t&)) const
}
先分析先序遍歷效果:如上圖先序遍歷的順序為abcdefghk。
根總是先被訪問,之後被訪問的就是他的左孩子,左孩子又稱為新的根,於是繼續訪問他的左孩子,直到這個根沒有左孩子,之後訪問他的右兒子,如果他沒有右兒子,如圖中的d,追溯到他的父節點去訪問右兒子,一直追溯,直到有了右兒子,如e是a的右兒子,e又作為新的根節點先被訪問 ,繼續一開始的遍歷。
可能要被我繞暈了,簡言之,得到根節點之後先對其訪問,然後要訪問全部的左兒子,最後再是右兒子。所以,一顆子樹的右兒子要放在最後訪問,就好比壓在最下面,等上面的根和左兒子訪問過了在出來,於是,這裡我們用到了棧。
上**!
/*非遞迴先序遍歷*/
template void binarytree::norecurringpreorder(const node* rt, void(*visit)(const t&)) const
stacks;
node* temp = nullptr;
s.push(rt);
while (s.empty() == false)
if (temp->left_child != nullptr)
}}
子樹的左->根->右**:
/*中序遍歷*/ //左->根->右
template void binarytree::inorder(const node* rt, void(*visit)(const t&)) const
}
遍歷效果:上圖遍歷順序為bdcaehgkf遍歷思路:一路向左!直到這個左孩子作為根的時候沒有它自己的左孩子,那就先訪問他,因為此時按照遍歷順序左->根->右,他被當成根了(沒有左孩子),訪問他完之後就取訪問他的右兒子,繼續一路向左,重複過程...
偽**:當前根不為空的時候=>壓入=>他成為他的左兒子=>迴圈,如果當前是空=>取棧頂(當前根)訪問他,並且pop()=>他成為他的右兒子=>迴圈,棧空或者最初根為nullptr的時候退出。
上**:
/*非遞迴中序遍歷*/
template void binarytree::norecurringinorder(node* rt, void(*visit)(const t&)) const
else
}}
子樹的左->右->根**:
/*後序遍歷*/ //左->右->根
template void binarytree::postorder(const node* rt, void(*visit)(const t&)) const
}
遍歷效果:dcbhkgfea關於思路
後序遍歷的非遞迴就比前兩種的要複雜一點了,也比較難理解,因為根是最後被訪問的,而在棧頂的元素當做根的話並不知道他的兒子們有沒有被訪問過,所以開乙個棧不夠,起碼還要乙個棧來儲存乙個標記,這個標記用來記錄他的兒子們有沒有被訪問過。
關於方法
方法有很多種,可以開乙個布林棧放入對應根節點的標記,判斷當前根已經被訪問過兒子們了即可出棧,否則就壓入他的兩個兒子(按順序是先左後右,又因為棧的關係,所以先壓入右兒子)。
這裡呢我就介紹一種方法:開乙個棧,每次節點壓入都壓兩次,出棧的時候判斷棧頂元素是否和他相同,如果兩個相同,就說明他的兒子沒有被訪問(壓入棧),就先壓入他的右孩子,再左孩子,注意每次壓入都是壓兩個,空節點不入棧。
**:
/*非遞迴後序遍歷*/
void binarytree::norecurringpostorder(node* rt, void(*visit)(const t&)) const
stacks;
node* temp = rt;
s.push(temp);
s.push(temp);
while (s.empty() == false)
if (temp->left_child)
} else
}}
目前我看到的方法不管是開兩個棧還是乙個棧,需要的空間都是總節點數的兩倍。
按照層數從左往右依次遍歷
上圖遍歷效果:abecfdghk
思路:訪問的順序像排隊一樣逐層遍歷,每層的下面一層,按照從左到右的順序在當前層的最後排好隊,當前層也是按照從左往右的順序被排好了,那在訪問當前層的節點時將兒子們(下一層)排入尾,這樣就可以實現了。可以看成是一種遞推,把根看成最初的乙個人在排隊
上**:
/*層序遍歷,利用佇列,也可以利用陣列,然後用兩個指標去控制入和出*/
template void binarytree::levelorder(node* rt, void(*visit)(const t&)) const
while (!q.empty())
if (temp->right_child)
}}
還有一種利用陣列來實現的方法,網上找到的,大致思路其實就是用陣列實現了佇列的功能:通過兩個指標 in out(都是下標)控制,個人認為會浪費資源空間,不過思路很好。
void floorprint(ptreenode tree) //層序遍歷
out++; }}
原文:
二叉樹的遍歷很重要(我們老師是這麼說的。。可能只是為了應付考試吧)我還是比較推薦在理解的基礎上掌握知識,要不斷的在腦海中模擬遍歷的過程,遞迴的和非遞迴的。 二叉樹相關演算法(一) 二叉樹的遍歷
遞迴方式會導致每個節點會經過三次,先序是在第一次經過節點時訪問,中序是第二次經過節點時訪問,後序是第三次經過節點時訪問。其中較為特殊的是葉子節點,左孩子和右孩子都為空,訪問空樹時什麼都不做就返回。public static void p node h 1 利用棧來進行實現,三種演算法在理解的基礎上進...
設計性實驗一 二叉樹的遍歷
一 實驗任務 二叉樹的遍歷 分別以順序儲存結構和二叉鍊錶作儲存結構,試編寫前序 中序 後序及層次順序遍歷二叉樹的演算法。二 實驗任務的子任務 本人設計以二叉鍊錶作儲存結構,編寫前序 中序 後序及層次順序遍歷二叉樹的演算法。三 演算法分析 如圖 文字或流程圖或畫圖說明都可 1.假設輸入的資料即為乙個二...
二叉樹學習(一)二叉樹基礎
最近準備學習一下資料結構,二叉樹當然是必須要了解的了。網上看了一些貼子,順便把重要的內容就記下來了,有需要的同學可以看看,入門看很有幫助。1.1 定義 1.2 結點的度 1.3 結點關係 1.4 結點層次 2.1 定義 2.2 二叉樹特點 每個結點最多有兩顆子樹,所以二叉樹中不存在度大於2的結點。左...