特殊二叉树的判断(平衡二叉树,搜索二叉树,完全二叉树)
平衡二叉树
判断是否为平衡二叉树,需要注意以下三点:
- 左子树是否为平衡二叉树
- 右子树是否为平衡二叉树
- 左右子树的高度差小于等于1
bool isBalanced(TreeNode* root) {
if(!root)
return true;
if(abs(countFloor(root->left)-countFloor(root->right))>1) //左右子树高度差
return false;
else
{
if(isBalanced(root->left) && isBalanced(root->right)) //左右子树是否都为平衡二叉树
{
return true;
}
else
return false;
}
}
int countFloor(TreeNode* root) //计算树的深度
{
if(!root)
return 0;
return 1+max(countFloor(root->left),countFloor(root->right));
}
搜索二叉树
将二叉树进行中序遍历,得到的结果是完全升序的二叉树就是搜索二叉树。
bool isVaildBST(TreeNode* root)
{
stack<TreeNode*> tmp;
int min = INT_MIN;
while(root != NULL || !tmp.empty())
{
if(root != NULL)
{
tmp.push(root);
root = root->left;
}
else
{
TreeNode* cur = tmp.top();
tmp.pop();
if(cur->val <= min)
return false;
min = cur->val;
root = cur->right;
}
}
return true;
}
完全二叉树
在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h 个节点。
可以通过层次遍历进行判断,出现以下情况一定不是完全二叉树。
- 节点只有右儿子没有左儿子。
- 已经出现一个节点为叶节点,在对之后的节点遍历时存在节点不为叶节点。
bool isVaildCBT(TreeNode* root)
{
queue<TreeNode*> q1;
bool leaf = false;
if(root == NULL)
return true;
q1.push(root);
while(!q1.empty())
{
TreeNode* cur = q1.front();
q1.pop();
if(cur->left == NULL && cur->right != NULL) //存在右儿子但是没有左儿子
return false;
if(leaf && (cur->left != NULL || cur->right != NULL)) //在出现叶节点之后存在非叶节点
return false;
if(cur->left != NULL)
q1.push(cur->left);
if(cur->right != NULL)
q1.push(cur->right);
else
leaf = true;
}
return true;
}
求完全二叉树的节点个数
最简单的方法是遍历整个二叉树,但是这样时间复杂度很高。如果要求时间复杂度小于O(N),可以利用完全二叉树的特性来简化过程。完全二叉树的最后一层,节点一定是从左向右连续排列的。完全二叉树里一定有满的子树,而满二叉树的节点个数可以由树高直接得出,是2^h-1。所以通过判断这个完全二叉树中作为满二叉树的子树,就可以在小于O(N)的时间里得出节点数目。
O
/ \
O O
/ \ / \
O O O O
/ \ / \
O O O O
在一个节点的左子树的左路到达最底层,而右节点的左路没有到达底层,说明右子树为满二叉树,根据右子树的树高k可以得到节点数为2^k-1,加上根节点共有2^k个节点。
O
/ \
O O
/ \ / \
O O O O
/ \ / \
O O O O
如果左子树的左路没有到达最底层,而右节点的左路到底底层,与上同理。
int countNodes(TreeNode* root)
{
if (root == NULL)
return 0;
return countBS(root, 1, mostleftlevel(root, 1));
}
int countBS(TreeNode* head, int level, int depth)
{
if (level == depth) //当层数与深度相等,仅有一个节点
return 1;
if (mostleftlevel(head->right, level + 1) == depth) //左子树为满树
return (1 << (depth - level)) + countBS(head->right, level + 1, depth);
else //右子树为满树
return (1 << (depth - level - 1)) + countBS(head->left, level + 1, depth);
}
int mostleftlevel(TreeNode* node, int level) //计算一个节点的左路深度
{
while (node != NULL)
{
level++;
node = node->left;
}
return level - 1;
}