如何計算完全二叉樹的節點數


 

https://labuladong.gitee.io/algo/2/18/31/

 

讀完本文,你不僅學會了算法套路,還可以順便去 LeetCode 上拿下如下題目:

222.完全二叉樹的節點個數(中等)

———–

如果讓你數一下一棵普通二叉樹有多少個節點,這很簡單,只要在二叉樹的遍歷框架上加一點代碼就行了。

但是,如果給你一棵完全二叉樹,讓你計算它的節點個數,你會不會?算法的時間復雜度是多少?這個算法的時間復雜度應該是 O(logN*logN),如果你心中的算法沒有達到高效,那么本文就是給你寫的。

首先要明確一下兩個關於二叉樹的名詞「完全二叉樹」和「滿二叉樹」。

我們說的完全二叉樹如下圖,每一層都是緊湊靠左排列的:

我們說的滿二叉樹如下圖,是一種特殊的完全二叉樹,每層都是是滿的,像一個穩定的三角形:

說句題外話,關於這兩個定義,中文語境和英文語境似乎有點區別,我們說的完全二叉樹對應英文 Complete Binary Tree,沒有問題。但是我們說的滿二叉樹對應英文 Perfect Binary Tree,而英文中的 Full Binary Tree 是指一棵二叉樹的所有節點要么沒有孩子節點,要么有兩個孩子節點。如下:

以上定義出自 wikipedia,這里就是順便一提,其實名詞叫什么都無所謂,重要的是算法操作。本文就按我們中文的語境,記住「滿二叉樹」和「完全二叉樹」的區別,等會會用到。

一、思路分析

現在回歸正題,如何求一棵完全二叉樹的節點個數呢?

// 輸入一棵完全二叉樹,返回節點總數 int countNodes(TreeNode root); 

如果是一個普通二叉樹,顯然只要向下面這樣遍歷一邊即可,時間復雜度 O(N):

public int countNodes(TreeNode root) { if (root == null) return 0; return 1 + countNodes(root.left) + countNodes(root.right); } 

那如果是一棵滿二叉樹,節點總數就和樹的高度呈指數關系:

public int countNodes(TreeNode root) { int h = 0; // 計算樹的高度 while (root != null) { root = root.left; h++; } // 節點總數就是 2^h - 1 return (int)Math.pow(2, h) - 1; } 

完全二叉樹比普通二叉樹特殊,但又沒有滿二叉樹那么特殊,計算它的節點總數,可以說是普通二叉樹和完全二叉樹的結合版,先看代碼:

public int countNodes(TreeNode root) { TreeNode l = root, r = root; // 記錄左、右子樹的高度 int hl = 0, hr = 0; while (l != null) { l = l.left; hl++; } while (r != null) { r = r.right; hr++; } // 如果左右子樹的高度相同,則是一棵滿二叉樹 if (hl == hr) { return (int)Math.pow(2, hl) - 1; } // 如果左右高度不同,則按照普通二叉樹的邏輯計算 return 1 + countNodes(root.left) + countNodes(root.right); } 

結合剛才針對滿二叉樹和普通二叉樹的算法,上面這段代碼應該不難理解,就是一個結合版,但是其中降低時間復雜度的技巧是非常微妙的。

二、復雜度分析

開頭說了,這個算法的時間復雜度是 O(logN*logN),這是怎么算出來的呢?

直覺感覺好像最壞情況下是 O(N*logN) 吧,因為之前的 while 需要 logN 的時間,最后要 O(N) 的時間向左右子樹遞歸:

return 1 + countNodes(root.left) + countNodes(root.right); 

關鍵點在於,這兩個遞歸只有一個會真的遞歸下去,另一個一定會觸發 hl == hr 而立即返回,不會遞歸下去。

為什么呢?原因如下:

一棵完全二叉樹的兩棵子樹,至少有一棵是滿二叉樹:

看圖就明顯了吧,由於完全二叉樹的性質,其子樹一定有一棵是滿的,所以一定會觸發 hl == hr,只消耗 O(logN) 的復雜度而不會繼續遞歸。

綜上,算法的遞歸深度就是樹的高度 O(logN),每次遞歸所花費的時間就是 while 循環,需要 O(logN),所以總體的時間復雜度是 O(logN*logN)。

所以說,「完全二叉樹」這個概念還是有它存在的原因的,不僅適用於數組實現二叉堆,而且連計算節點總數這種看起來簡單的操作都有高效的算法實現。

_____________


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM