Given a complete binary tree, count the number of nodes.
Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.
题目要求:给你一个完全二叉树,求总共的节点数。
原始方法:
int countNodes(TreeNode* root) {
if(!root) return 0;
return countNodes(root->left)+countNodes(root->right)+1;
}
这里的算法复杂度是:
O(n)
因为这里的二叉树的特点是完全二叉树,因此可以根据这个特点进行优化。
/*
eg1:有如下的一颗完全二叉树(左孩子满)
o
/ \
o o
/ \ / \
o o o o
/ \/ \/
o oo oo
如果完全二叉树的最后一行是满的,那么它左孩子和右孩子的高度应该是一样的。这里先求得
root根节点的高度h,如果右孩子的高度恰好为h-1,那么说明它的左孩子必定是满的(最后一行部空)。此时,可以确定它的左孩子的总节点数是2^h-1个,加上一个根节点,目前计数为2^h个。如下所示:
x
/ \
x o <- 新的根节点
/ \ / \
x x o o
/ \ / \/
x x x xo
(x是已经计数的,o是未计数的)
此时,只再需要对它的右孩子进行计数即可。
以上讨论的是第一种情况,左孩子满的情况,还有可能左孩子不是满的,如下图所示。此时,右孩子必定也是一颗满的完全二叉树,但此时它的高度是h-2,故此时右孩子的节点总数为2^(h-1)-1, 此时加上根节点总数为2^(h-1)个。再对左孩子进行计数。
eg2:有如下的一颗完全二叉树(左孩子不满)
o
/ \
o o
/ \ / \
o o o o
/ \/
o oo
对右孩子进行计完树之后,再对左孩子计数。
x
/ \
新的根节点 -> o x
/ \ / \
o o x x
/ \/
o oo
(x是已经计数的,o是未计数的)
*/
int countNodes(TreeNode* root) {
// int h=height(root);
// return h<0?0:height(root->right)==h-1?(1<<h)+countNodes(root->right):(1<<h-1)+countNodes(root->left);
int nodes=0,h=height(root);
while(root!=nullptr)
{
if(height(root->right)==h-1)
{
nodes+=1<<h;
root=root->right;
}else
{
nodes+=1<<(h-1);
root=root->left;
}
h--;
}
return nodes;
}
int height(TreeNode* root)
{
return root==NULL?-1:1+height(root->left);
}
此时的时间复杂度是:
O(logn)
原文来自StefanPochmann,自己翻译了下,加点注解。