題目:輸入一棵二叉樹的根結點,判斷該樹是不是平衡二叉樹。如果某二叉樹中任意結點的左右子樹的深度相差不超過1,那麼它就是一棵平衡二叉樹。例如下圖中的二叉樹就是一棵平衡二叉樹:
在本系列部落格的第27題,我們曾介紹過如何求二叉樹的深度。有了求二叉樹的深度的經驗之後再解決這個問題,我們很容易就能想到一個思路:在遍曆樹的每個結點的時候,調用函數TreeDepth得到它的左右子樹的深度。如果每個結點的左右子樹的深度相差都不超過1,按照定義它就是一棵平衡的二叉樹。這種思路對應的代碼如下:
bool IsBalanced(BinaryTreeNode* pRoot){ if(pRoot == NULL) return true; int left = TreeDepth(pRoot->m_pLeft); int right = TreeDepth(pRoot->m_pRight); int diff = left - right; if(diff > 1 || diff < -1) return false; return IsBalanced(pRoot->m_pLeft) && IsBalanced(pRoot->m_pRight);}
上面的代碼固然簡潔,但我們也要注意到由於一個節點會被重複遍曆多次,這種思路的時間效率不高。例如在函數IsBalance中輸入上圖中的二叉樹,首先判斷根結點(值為1的結點)的左右子樹是不是平衡結點。此時我們將往函數TreeDepth輸入左子樹根結點(值為2的結點),需要遍曆結點4、5、7。接下來判斷以值為2的結點為根結點的子樹是不是平衡樹的時候,仍然會遍曆結點4、5、7。毫無疑問,重複遍曆同一個結點會影響效能。接下來我們尋找不需要重複遍曆的演算法。
如果我們用後序遍曆的方式遍曆二叉樹的每一個結點,在遍曆到一個結點之前我們已經遍曆了它的左右子樹。只要在遍曆每個結點的時候記錄它的深度(某一結點的深度等於它到分葉節點的路徑的長度),我們就可以一邊遍曆一邊判斷每個結點是不是平衡的。下面是這種思路的參考代碼:
bool IsBalanced(BinaryTreeNode* pRoot, int* pDepth){ if(pRoot == NULL) { *pDepth = 0; return true; } int left, right; if(IsBalanced(pRoot->m_pLeft, &left) && IsBalanced(pRoot->m_pRight, &right)) { int diff = left - right; if(diff <= 1 && diff >= -1) { *pDepth = 1 + (left > right ? left : right); return true; } } return false;}
我們只需要給上面的函數傳入二叉樹的根結點以及一個表示結點深度的整形變數就可以了:
bool IsBalanced(BinaryTreeNode* pRoot){ int depth = 0; return IsBalanced(pRoot, &depth);}
在上面的代碼中,我們用後序遍曆的方式遍曆整棵二叉樹。在遍曆某結點的左右子結點之後,我們可以根據它的左右子結點的深度判斷它是不是平衡的,並得到當前結點的深度。當最後遍曆到樹的根結點的時候,也就判斷了整棵二叉樹是不是平衡二叉樹了。
博主何海濤對本部落格文章享有著作權。網路轉載請註明出處http://zhedahht.blog.163.com/。整理出版物請和作者聯絡。對解題思路有任何建議,歡迎在評論中告知,或者加我微博http://weibo.com/zhedahht或者http://t.163.com/zhedahht與我討論。謝謝。