特殊二叉树的判断(平衡二叉树,搜索二叉树,完全二叉树)

平衡二叉树

判断是否为平衡二叉树,需要注意以下三点:

  • 左子树是否为平衡二叉树
  • 右子树是否为平衡二叉树
  • 左右子树的高度差小于等于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;
}
posted @ 2019-06-25 17:26  番茄起司汤  阅读(251)  评论(0编辑  收藏  举报