您的位置:首页 > 其它

完全二叉树统计节点个数【使用二分搜索】

2016-12-16 02:29 211 查看
【题目】

给定一棵完全二叉树的根节点root,返回这棵树的节点个数。如果完全二叉树的节点数为N,请实现时间复杂度低于O(N)的解法。

给定树的根结点root,请返回树的大小。


”打眼“一看,这是一道递归求解数的高度的题,于是我不到30秒敲了几行代码就解决:

class CountNodes {
public:
int count(TreeNode* root) {
if(root == NULL)
return 0;
else
return count(root->left) + count(root->right) + 1;
}
};


现在我们来分析一下时间复杂度,这种方法每个节点遍历一次时间复杂度为O(N),并且空间复杂度为递归栈的消耗,也是O(N)。

貌似,还行。不过有更好的解决方案。

我们知道二叉树有几条性质:

1:一般情况下,完全二叉树层数等于高度,都从1开始(不过有时候高度=层数+1,层数从0开始,视具体情况而定)。
2:高度为h的满二叉树,有(2^h)-1个结点。(可以举例有3个节点的完全二叉树,高度为2,结点数目为2^2-1。
3:具有n个结点的完全二叉树的高度为log(n+1)。(这个从上面高度的公式可以推出)
4:第k层至多有2^(k-1)个结点。(同样从上面可推得,这句高度就等于层数,实际情况下我们还是不要死记公式,每次画3个结点自己推一下不就得了)。

好了,知道了这几个性质,下面就可以来探讨一下本题完全二叉树使用二分搜索的解法,不过不得不说,在我们自己计算的时候,一半把高度和层数统一最好,不会算出纰漏。

先上第二种解法的代码,以下解决方案仅针对本题完全二叉树的题型:
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/

class CountNodes {
public:
int count(TreeNode* root) {
if(root == NULL)
return 0;
return bs(root, 1, max_left_level(root, 1));  //in this solution, height == level
}
private:
int bs(TreeNode* t, int l, int h){
if(l == h)       //if left child and right child is NULL, then l == h, return 1
return 1;
if(max_left_level(t->right, l+1) == h)
return (1 << (h-l)) + bs(t->right, l+1, h);  //1<<(h-l) means 2^(h-l)-1+1
else
return (1 << (h-l-1)) + bs(t->left, l+1, h);
}

int max_left_level(TreeNode* t, int level){
while(t != NULL){
++level;   //level will be real level+1
t = t->left;
}
return --level;  //return real level
}
};


在本题中,利用完全二叉树的特性,我们用二分搜索的方法来解答。本题中高度=层数。
由于完全二叉树,没有左子树不可能有右子树。我们先计算完全二叉树的左侧高度,然后再计算根节点右孩子最左下侧孩子的高度,有两种情况:
1.高度相等
说明两侧最后一层处于同一层,如下图(1),由于是完全二叉树,红色结点存在,则绿色结点必然存在,左半部分必然是一棵满二叉树。这时我们就可以用上文中的
性质2,高度为h的满二叉树,结点个数为2^h-1,直接套公式就解决了根结点左侧不过包括根结点的结点数目,我们再加上根结点,我们现在要解决的问题又转化成了在根结点的右子树中以同样的方法求结点数目。当然可能遇到高度不等的情况,即情况2。
2.高度不等
说明后者比前者第一层,不过也只能是一层,因为是完全二叉树,如图(2),红色节点比绿色节点少一层。这时我们就不能直接计算左边的数目了,但是,类似的,同样由于完全二叉树的性质,我们的右半部份又成了一棵满二叉树,我们对右半部份利用公式计算即可。然后再计算左半部分。



不难看出这是一个递归的过程,递归中会主要有两种情况,就是红色结点和绿色结点高度是否相等,采取不同的计算方法。

值得注意的是,递归终止条件的确立。我们从根结点来推算。
如果只有根节点,它的左右子树为空,那么它高度为1,结点数目为1,所以我们可以推得当一个结点没有左右子树时,直接返回1,因为它这棵子树就只有它这一个结点。这也蕴含了递归的思想。

好吧,这道题先到这里。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息