其實關於這個東西呢,網路上已經有各種資料跟code可以看了
比如說這個:https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/
我只是想紀錄一下,讓自己比較有印象而已XD
大概可以分成inorder、preorder、postorder和levelorder四種
前面三種又是俗稱的depth-first search(深度優先搜尋),只是輸出的順序不一樣
levelorder又可以叫做breath-first search(好像叫廣度優先搜尋)
有什麼區別呢,接下來就來看看
1. inorder:
會依照左邊,root,右邊的順序去尋訪
code的話比較常見是用遞迴的方式去做,假設我要印出節點裡的值:
void inorder(TreeNode* root)
{
if (root == nullptr) return;
inorder(root->left);
cout << root->val;
inorder(root->right);
}
除了用遞迴之外,也可以用stack的方式來做
就是把root先存到stack裡面, 然後利用stack先進後出的特性來做
void inorder(TreeNode* root)
{
stack<TreeNode*> s;
TreeNode* cur = root;
while (cur != nullptr || !s.empty())
{
while (cur->left)
{
s.push(cur);
cur = cur->left;
}
// 跳出上面那個迴圈,表示已經沒有左子樹了
cur = s.top(); // 此時stack中最上面的節點就會是最左邊子樹的節點
cout << cur->val;
s.pop();
cur = cur->right; // 如果有右子樹的話,就要從現在節點的右子樹開始尋訪
}
}
對於BST(binary search tree)來說,如果用inorder的方式尋訪,就會印出排好序的數列
貌似很多題目都會用到這個特性
2. preorder:
就是root -> left -> right
常見的也是用遞迴來做
code大概長成這樣:
void preorder(TreeNode* root)
{
if (root == nullptr) return;
cout << root->val;
preorder(root->left);
preorder(root->right);
}
有發現嗎,其實只是換個順序而已
所以對於tree的traversal這個問題來說,遞迴的概念就很重要了
比需要對遞迴有一定的熟悉,才能夠應用到不同的情況
3. postorder
和上面差不多,換個順序而已
void postorder(TreeNode* root)
{
if (root == nullptr) return;
postorder(root->left);
postorder(root->right);
cout << root->val;
}
應該不會很難懂吧,主要還是熟悉度的問題
再來這一個比較不一樣
4. levelorder
意思就是從level最小的開始尋訪,從最上層開始往下找這樣
這個可以用遞迴或是用queue來做
個人覺得用queue的方式比較好做,就先看怎麼用queue的方式做吧:
註:這段是來自https://www.geeksforgeeks.org/level-order-tree-traversal/的,因為這排版實在很難打字...
雖說上面這樣可以把所有值依照順序印出來,不過如果要算level之類的東西的話,我會稍微加一點東西:
這樣等於是一層一層的尋訪,個人覺得比較有feel
遞迴的話要先知道總共有幾個level,所以要有一些輔助的function:
這些code也是來自https://www.geeksforgeeks.org/level-order-tree-traversal/的
有些code可以參考一下做法,滿受用的
這個做法也是一層一層的印,不過有點麻煩的是要先知道level是多少
大概解紹了幾種tree traversal的方法,中間參考了很多別的網站上的介紹
主要還是要有辦法內化成自己的東西啦,或是把其中的一些概念應用到別的地方
希望能夠藉由記錄來讓自己印象更深刻,那就這樣了~
留言列表