樹的遍歷和迭代的一些總結
一直在寫effective stl的總結,今天換個主題,我們來看看演算法,刷leetcode看到了樹的遍歷的問題和一些迭代的問題,順便過來總結一番.
-
首先我們來看看mergeTree,是leetcode上面的merge two binary trees:
題目如上圖所示,我們下面來分析一下我們的思路,首先肯定是需要理解題目要幹什麼,題目的意思就是讓我們把兩個樹"加"起來,類似於去兩個樹的並集.
接下來,我們肯定要想到迭代啊,因為這種問題都是由一個小的部分可以放大到一個大的部分,針對這個題就是說我們如果我們融合了這兩顆的子樹,那麼我們只需要將根節點相加就完成了,所以以遞迴的思想來看就是,我們不斷的對根節點的子節點呼叫mergeTrees,這樣最終會讓所有子樹都完成相"加",這樣一層一層擴充就完成了整個樹的相"加".
然後就是要考慮迭代函式結束的時候了,因為迭代從大的樹的根節點到越來越小的樹的根節點,最終肯定要結束的,不然迭代就結束不了了.對於我們來說,這個迭代函式的結束情況很簡單,如果兩個節點有任意一個為空,那麼迭代就結束,直接返回另外一個節點即可(這時我們不用考慮另外一個節點是否為空,原因很簡單).
這個時候,我們程式的框架就完成了.
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
if (!t1) return t2;
if (!t2) return t1;
TreeNode* node = new TreeNode(t1->val + t2->val);
node->left = mergeTrees(t1->left, t2->left);
node->right = mergeTrees(t1->right, t2->right);
return node;
}
};
理解起來應該並不讓人覺得困難,主要是我們要弄清楚迭代的思路.
-
接下來說的也是一個迭代的例子,題目也是leetcode上的flatten-binary-tree-to-linked-list:
這個題目乍一看不算簡單,需要我們的思考才能解決問題,這個問題依然是用遞迴來解決的,原因還是和上面一樣.不過這次的迭代函式需要我們來深思一下了,因為遞迴沒有那麼容易了.
首先,我們考慮下迭代函式是在做什麼.對於一個最簡單的樹,如果我們呼叫迭代函式,要想將樹"flatten",那麼我們先要將根節點的右節點連到左節點的右子節點上,然後在將左子樹連到根節點的右子節點上.
我畫了個圖,大家看看:手動畫圖,有點粗糙,不過畫了圖我們要做的事情就變得明朗起來.
迭代函式的引數是root節點,要做的就是將樹"flatten",返回值的話可以是void也可以是root節點,如果是void的話,我們就要加入一個額外的變數來儲存節點.我們這裡假設返回值是void吧(因為leetcode上給的解題模板就是函式返回值為空,其實返回一個指標也OK),加入一個額外的TreeNode指標prev.迭代函式內部要完成我在圖中畫的三步,第一步之前,先令prev為右子節點的指標(也就是指向3的TreeNode指標).第一步到第二步的過程中,讓左子節點的right等於prev,再讓root的右子節點為空(root->right=NULL),用prev來儲存左子節點指標(也就是指向2的TreeNode指標).第二步到第三步的過程,我們令root的右子節點為prev(也就是指向2的TreeNode指標),然後再令左子節點為空,最後令prev為root節點就OK了.
這個時候,規律已經很明顯了,程式碼如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void flatten(TreeNode* root) {
if(root == NULL)
return;
flatten(root->right);
flatten(root->left);
root->right=prev;
root->left = NULL;
prev = root;
}
private:
TreeNode *prev = NULL;
};
- 我們稍稍總結一下迭代這一部分,迭代的問題都是有規律的,也就是說對於一個大的問題,它的解法實際上是和小的問題是類似的,譬如我們上面的樹的例子,都是對根節點進行操作,然後呢,對左右子節點呼叫同樣的函式(因為子節點仍然還是樹,函式依然是正確的),當節點已經沒有子節點時,迭代就結束了,然後迭代會不斷返回,最終一顆大樹的問題也解決了.
相關文章
- 遍歷二叉樹的迭代和遞迴方法二叉樹遞迴
- 二叉樹的遍歷 (迭代法)二叉樹
- 二叉樹遍歷方法總結二叉樹
- 94. 二叉樹的中序遍歷(迭代)二叉樹
- 遍歷物件和陣列的方法總結物件陣列
- 二叉樹的廣度遍歷和深度遍歷()二叉樹
- 樹的遍歷方式
- Javascript樹(一):廣度遍歷和深度遍歷JavaScript
- Java中用遞迴和迭代實現二叉樹的中序( InOrder )遍歷Java遞迴二叉樹
- 二叉樹的前序,中序,後序遍歷方法總結二叉樹
- Jvascript陣列迭代,遍歷的方法陣列
- 資料結構——樹與二叉樹的遍歷資料結構二叉樹
- Python資料結構——解析樹及樹的遍歷Python資料結構
- 關於Map集合的遍歷總結
- [資料結構]二叉樹的前中後序遍歷(遞迴+迭代實現)資料結構二叉樹遞迴
- javascript遍歷方法總結JavaScript
- JS遍歷方法總結JS
- 二叉樹的深度優先遍歷和廣度優先遍歷二叉樹
- 二叉樹的建立、前序遍歷、中序遍歷、後序遍歷二叉樹
- 二叉樹排序樹的建立,遍歷和刪除二叉樹排序
- 根據二叉樹的前序遍歷和中序遍歷輸出二叉樹;二叉樹
- 資料結構與演算法——二叉樹的前序遍歷,中序遍歷,後序遍歷資料結構演算法二叉樹
- 樹的遍歷c/c++C++
- 二叉樹的遍歷二叉樹
- js的map遍歷和array遍歷JS
- 劍指offer:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。二叉樹
- 二叉樹的遍歷演算法【和森林的遍歷】【PHP 原始碼測試】二叉樹演算法PHP原始碼
- LintCode 前序遍歷和中序遍歷樹構造二叉樹二叉樹
- JavaScript遍歷物件方法總結JavaScript物件
- map遍歷知識總結
- 讓Vue的v-for支援迭代器遍歷Vue
- 玩轉二叉樹(樹的遍歷)二叉樹
- 【根據前序和中序遍歷構造二叉樹】棧+迭代 || 遞迴二叉樹遞迴
- JavaScript 遍歷、列舉與迭代JavaScript
- 完全二叉樹的遍歷二叉樹
- MySQL 實現樹形的遍歷MySql
- 線索二叉樹的構造和遍歷二叉樹
- 【資料結構】二叉樹的建立與遍歷資料結構二叉樹