完全二叉树的节点个数
1.三种解法
迭代法–层序遍历
直接层序遍历遍历所有节点,然后统计个数即可。
代码如下:
def countNodes(self, root):
"""
:type root: TreeNode
:rtype: int
"""
queue = []
result = []
if not root:
return 0
queue.append(root)
while queue:
size = len(queue)
for i in range(size):
node = queue.pop(0)
result.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return len(result)
时间复杂度
O
(
n
)
O(n)
O(n)
空间复杂度
O
(
n
)
O(n)
O(n)
递归法–后序遍历
使用后序遍历的逻辑(左右中),代码如下:
def countNodes(root):
if not root:
return 0
leftchild_num = countNodes(root.left) # 左
rightchild_num = countNodes(root.right) # 右
return leftchild_num+rightchild_num+1 # 中
时间复杂度
O
(
n
)
O(n)
O(n)
空间复杂度
O
(
l
o
g
2
n
)
O(log_2n)
O(log2n)
递归法–完全二叉树性质
如果我们想求一棵完全二叉树的节点数目,利用完全二叉树的性质,他的节点个数应该为1~ 2 h − 1 2^h-1 2h−1,h为树的深度。最大值在该树是满二叉树时取得。
所以对于满二叉树,我们是有计算公式的,所以我们要利用这个性质,用递归的方法,策略如下:
- 如果某个节点是满二叉树的根节点,那么我可以直接用公式计算这棵树的节点个数
- 如果某个节点不是满二叉树的根节点,那么我们就来探测他的左子树和右子树是不是满二叉树的根节点。
(1)如果是则用公式计算出来,然后原树的节点个数就是左子树的节点数+右子树的节点数+1.
(2)如果不是则在探测左子树的左子树和右子树、右子树的左子树和右子树是不是满二叉树。
判断满二叉树的方式就是,计算出从该节点一直向左的深度和一直向右的深度是不是相等。
这样以来我们就能看出重复操作了,所以就可以这样写代码:
def countNodes(self, root: TreeNode) -> int:
if not root:
return 0
left = root.left
right = root.right
leftHeight = 0 #这里初始为0是有目的的,为了下面求指数方便
rightHeight = 0
while left: #求左子树深度
left = left.left
leftHeight += 1
while right: #求右子树深度
right = right.right
rightHeight += 1
# 如果是满二叉树
if leftHeight == rightHeight:
return (2 << leftHeight) - 1 #注意(2<<1) 相当于2^2,所以leftHeight初始为0
# 如果不是满二叉树
return self.countNodes(root.left) + self.countNodes(root.right) + 1
2.总结
注意二叉树和完全二叉树的一些性质:
- 在二叉树上的第 i 层上至多有 2 i − 1 2^{i-1} 2i−1 个节点(i>=1)
- 深度为 k 的二叉树至多有 2 k − 1 2^k-1 2k−1 个节点(k>=1)
- 具有n个节点的完全二叉树的深度为 └ l o g 2 n ┘ └log2n┘ └log2n┘+ 1
- 如果对一颗有n个节点的完全二叉树(其深度为 └ l o g 2 n ┘ + 1 └log2n┘+1 └log2n┘+1)的节点按层序编号,对于任意节点i有:
如果i=1,则节点i是二叉树的根节点,无双亲;
如果i>1,则其双亲节点是 └ i / 2 ┘ └i/2┘ └i/2┘
如果2i>n,则节点 i 无左孩子;否则其左孩子就是 2i
如果2i+1>n,则节点 i 无有右孩子;否则其右孩子就是 2i+1
- n0:树中度为0的节点的总数
n1:树中度为1的节点的总数
n2:树中度为2的节点的总数
n:总结点数
n0 = n2+1
n = n0 + n1 + n2