二叉樹,結構很簡單,只是比單鏈表複雜了那麼一丟丟而已。我們先來看看它們結點上的差異:
/*單鏈表的結構
*/struct
singlelist;
/*二叉樹的結構
*/struct
binarytree;
根據以上兩個結構,我們不難發現,單鏈表的結點只有乙個指向下一結點的指標,而二叉樹中有兩個。也就是說單鏈表每個結點只有乙個子節點,而二叉樹有兩個子節點(其中乙個可能為null)。了解了這一點的區別,我們就知道:基於二叉樹的演算法比基於單鏈表的演算法差異就是每次遍歷乙個結點之後,需要遍歷兩個子節點,而單鏈表只需要遍歷乙個子節點。
這就引出了2種遍歷的方法:廣度優先遍歷(bfs)和深度優先遍歷(dfs)。
對於單鏈表來說,bfs和dfs是一樣的,因為每個節點只有乙個子節點,每次遍歷下乙個節點只有一種選擇;但是二叉樹每個節點有兩個子節點,也就是說遍歷的順序既可以遍歷它的子節點(無論左節點還是右結點都是dfs),也可以遍歷它的兄弟結點。如果是每次先遍歷子節點那麼就是dfs;每次先遍歷兄弟結點,就是bfs。
dfs採用棧結構,博主這裡用的是遞迴來實現棧,當然大家也可以用stack來實現;bfs採用的是佇列queue。
void dfs(binarytree *root)
void bfs(binarytree *root)}
關於樹的一些演算法中,dfs和bfs一般都適用,但是當涉及到根到葉的路徑這類問題時,最好還是用dfs來實現。如下所示:
1、給一棵二叉樹和乙個值sum,求出所有從根到葉子的值等於sum的所有路徑。
思路:深度優先搜尋(dfs),然後把從跟開始每次訪問乙個結點就把該結點新增到乙個vec的最後位置,並把sum減去當前借點的值後傳遞給下乙個節點,當乙個結點的左右孩子都為null,並且值等於sum時,就說明該節點是葉子節點,並且從根結點到該節點的路徑和為sum,把vec,新增到res中;每次返回時,需要把vec中的最後乙個值刪除,因為每個節點有兩個子節點,從根節點到左孩子的葉子的路徑與到右孩子葉子的路徑是不同的,所有每次訪問完左孩子或者右孩子需要把孩子的值從vec中刪除。
/** * definition for a binary tree node.
* struct treenode
* }; */
class
solution
_pathsum(root->left, sum-root->val);
if(root->left)
vec.pop_back();
_pathsum(root->right, sum-root->val);
if(root->right)
vec.pop_back();
}public
: vector
int>> pathsum(treenode* root, int
sum)
};
2、轉化二叉樹
把二叉樹:
4/\ 2
7 / \ /\13
69
轉化成
4/\ 7
2 / \ /\96
31
思路:這個既可以用dfs也可以用bfs,也就是遍歷每個節點,然後將它們的左右孩子互換即可。這裡採用bfs來實現:
/** * definition for a binary tree node.
* struct treenode
* }; */
class
solution
return
root;
}};
3、總結
只要掌握了dfs和bfs的思想,其它關於二叉樹的演算法基本上都是類似的,必要的時候通過畫圖來讓自己感性認識一下也是極好的。
關於leetcode上的題目**:
leetcode 二叉樹 對稱二叉樹
給定乙個二叉樹,檢查它是否是映象對稱的。例如,二叉樹 1,2,2,3,4,4,3 是對稱的。1 2 2 3 4 4 3 但是下面這個 1,2,2,null,3,null,3 則不是映象對稱的 1 2 2 3 3 方法一 遞迴 思路 如果乙個樹的左子樹與右子樹映象對稱,則該樹是對稱的 兩個樹互為映象的...
LeetCode (二叉樹)反轉二叉樹
遞迴交換每乙個節點的左右子樹,重點在於訪問每乙個節點,然後交換左右子樹 definition for a binary tree node.struct treenode struct treenode inverttree struct treenode root 由於至少要講每乙個節點都訪問一次...
leetcode 二叉樹 二叉樹的層次遍歷
給定乙個二叉樹,返回其按層次遍歷的節點值。即逐層地,從左到右訪問所有節點 例如 給定二叉樹 3,9,20,null,null,15,7 3 9 20 15 7 返回其層次遍歷結果 3 9,20 15,7 方法一 遞迴 思路 比較訪問節點所在層次level和當前最高層次len levels 判定是否需...