判断一棵树是否是平衡二叉树及其时间复杂度的优化

本文介绍了平衡二叉树的基本概念及其实现方式,包括红黑树、AVL树、Treap、伸展树等,并提供了判断平衡二叉树的算法实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


定义:平衡二叉树(Self-balancing binary search tree)具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有 红黑树 AVL 替罪羊树 Treap 伸展树 等。 最小二叉平衡树的节点的公式如下 F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的 数列 ,可以参考Fibonacci(斐波那契)数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量。



红黑树

红黑树是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。它是在1972年由Rudolf Bayer发明的,他称之为"对称二叉B树",它现代的名字是在 Leo J. Guibas 和 Robert Sedgewick 于1978年写的一篇论文中获得的。它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n是树中元素的数目。

AVL

AVL是最先发明的自平衡二叉查找树算法。在AVL中任何节点的两个儿子子树的高度最大差别为一,所以它也被称为高度平衡树,n个结点的AVL树最大深度约1.44log2n。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。

Treap

Treap是一棵二叉排序树,它的左子树和右子树分别是一个 Treap,和一般的二叉排序树不同的是, Treap纪录一个额外的数据,就是优先级。 Treap在以关键码构成二叉排序树的同时,还满足 的性质(在这里我们假设节点的优先级大于该节点的孩子的优先级)。但是这里要注意的是 Treap二叉堆有一点不同,就是二叉堆必须是 完全二叉树,而 Treap并不一定是。

伸展树

伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入、查找和删除操作。它由Daniel Sleator和Robert Tarjan创造。它的优势在于不需要记录用于平衡树的 冗余信息。在 伸展树上的一般操作都基于伸展操作。

SBT

Size Balanced Tree(简称 SBT)是一自平衡二叉查找树,是在计算机科学中用到的一种数据结构。它是由中国广东 中山纪念中学的陈启峰发明的。陈启峰于2006年底完成论文《Size Balanced Tree》,并在2007年的 全国青少年信息学奥林匹克竞赛冬令营中发表。由于SBT的拼写很容易找到中文谐音,它常被中国的信息学竞赛选手和 ACM/ICPC选手们戏称为“傻B树”、“Super BT”等。相比红黑树、AVL树等自平衡二叉查找树,SBT更易于实现。据陈启峰在论文中称,SBT是“目前为止速度最快的高级二叉搜索树”。SBT能在O(log n)的时间内完成所有 二叉搜索树(BST)的相关操作,而与普通二叉搜索树相比,SBT仅仅加入了简洁的核心操作 Maintain。由于SBT赖以保持平衡的是size域而不是其他“无用”的域,它可以很方便地实现动态顺序统计中的 selectrank操作。

替罪羊树
替罪羊树是 计算机科学 中,一种基于部分重建的自平衡二叉搜索树。在替罪羊树上,插入或删除节点的平摊最坏 时间复杂度 O (log n),搜索节点的最坏时间复杂度是O(log n)。  
在非平衡的 二叉搜索树中,每次操作以后检查操作路径,找到最高的满足max(size(son_L),size(son_R))>alpha*size(this)的结点,重建整个子树。这样就得到了替罪羊树,而被重建的子树的原来的根就被称为替罪羊节点。




平衡二叉树:它是一棵空树或者左右子树的高度差绝对值不超过1,并且左右两棵子树都是平衡二叉树。

要判断一棵树是否是平衡二叉树,由其定义我们很容易想到通过计算出左右两棵子树的高度及其高度差来进行判断。

首先,判断当前节点是否是平衡二叉树,则需要开始遍历整棵树,求其左右子树的高度。递归判断其左右子树是否为平衡二叉树,又一次需要遍历其子树求其高度。多次求其高度,越接近叶子节点的节点高度被求的次数越多。 
这种方法很容易理解,但是它的时间复杂度是O(N*N),这是一种十分低效的算法。

既然导致低效的原因是因为多次求了节点的高度,因此,考虑将高度放在参数列表中,在递归的过程中返回给上一层。 
也就是说,从叶子节点开始判断这棵树是否是平衡二叉树。 
时间复杂度是O(N)

代码:

#include<iostream>
using namespace std;

struct Node
{
    int _data;
    Node* _left;
    Node* _right;
    Node(const int& x)
        : _data(x)
        , _left(NULL)
        , _right(NULL)
    {}
};

size_t Depth(Node* root)
{
    if (root == NULL)
        return 0;
    size_t left = Depth(root->_left);
    size_t right = Depth(root->_right);
    return left > right ? left + 1 : right + 1;
}
//bool IsBalanceN(Node* root)
//{//O(n*n)
//  if (root == NULL)
//      return true;
//  int leftDepth = Depth(root->_left);
//  int rightDepth = Depth(root->_right);
//  return abs(leftDepth - rightDepth) < 2 && IsBalance(root->_left) && IsBalance(root->_right);
//}

//时间复杂度为O(N)  bool _IsBalance(Node* root, int& depth){        	if (root == NULL)        {            depth = 0;            return true;        }        int ldepth = 0, rdepth = 0;        if (_IsBalance(root->_left, ldepth) == false)        {            return false;        }        if (_IsBalance(root->_right, rdepth) == false)        {            return false;        }        if (abs(ldepth - rdepth) > 1)        {            return false;        }        depth = ldepth > rdepth ? ldepth + 1 : rdepth + 1;//这棵子树已经是平衡二叉树了        return true;}


int main()
{
    Node* p1 = new Node(1);
    Node* p2 = new Node(1);
    Node* p3 = new Node(1);
    Node* p4 = new Node(1);
    Node* p5 = new Node(1);

    p1->_left = p2;
    p1->_right = p3;
    p2->_left = p4;
    p2->_right = p5;
    cout<<IsBalance(p1,0);

    return 0;
}

http://m.blog.youkuaiyun.com/qq_34992845/article/details/75041981

<think>我们被要求提供C语言代码来判断一棵二叉是否为平衡二叉树平衡二叉树的定义是:每个节点的左右子高度差不超过1,并且左右子也都是平衡二叉树。 根据引用[1]和引用[2]提供的思路,我们可以采用递归的方法。在递归计算的高度的同时,检查每个节点的左右子高度差是否超过1。如果超过1,则设置一个标记表示不平衡。 我们可以设计一个函数,它返回当前节点的高度,并且在递归过程中检查平衡性。如果发现不平衡,则通过一个全局变量或者通过指针传递的参数来记录不平衡的状态。 但是,使用全局变量并不是一个很好的做法,因为它使得函数不可重入。我们可以通过返回一个特殊值来表示不平衡(比如返回-1表示子不平衡),或者通过参数来传递平衡状态。 这里我们采用两种方法: 方法一:使用一个全局变量(如引用[1]中的BalanceTrue)来记录是否平衡。这种方法简单,但全局变量有副作用。 方法二:不使用全局变量,而是通过函数返回值同时传递高度和平衡信息。我们可以让函数在平衡时返回的高度,不平衡时返回-1(或者一个特殊值)。这样,我们可以通过检查返回值是否为-1来判断是否平衡。 我们选择方法二,因为它避免了全局变量,符合结构化编程的思想。 设计函数: int isBalancedHelper(TreeNode *root) 如果root为空,返回0(空高度为0,且平衡)。 否则,递归计算左子的高度leftHeight,如果leftHeight为-1,表示左子不平衡,则直接返回-1。 同样递归计算右子的高度rightHeight,如果rightHeight为-1,表示右子不平衡,则直接返回-1。 然后,检查左右子的高度差绝对值是否大于1,如果大于1,返回-1(表示当前节点为根的不平衡)。 否则,返回当前的高度(max(leftHeight, rightHeight)+1)。 最后,我们用一个包装函数: bool isBalanced(TreeNode *root) 调用isBalancedHelper(root),如果返回-1,则不平衡(返回false),否则平衡(返回true)。 注意:这种自底向上的递归方法,每个节点只访问一次,时间复杂度为O(n)。 下面我们根据引用[1]和引用[2]提供的代码风格,以及上述思路,写出C语言代码。 我们定义二叉节点结构体(如引用[1]所示): typedef struct TreeNode { int data; struct TreeNode *left; struct TreeNode *right; } TreeNode; 然后实现辅助函数和主判断函数。 注意:引用[1]中的代码使用了全局变量,而我们这里不使用全局变量,而是通过返回值传递状态。 代码实现:</think>### C语言实现平衡二叉树判断(递归法) 以下是判断二叉是否为平衡二叉树的完整C语言代码实现。平衡二叉树的定义:每个节点的左右子高度差不超过1,且所有子也满足该条件[^1][^2]。 ```c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> // 二叉节点结构 typedef struct TreeNode { int data; struct TreeNode *left; struct TreeNode *right; } TreeNode; // 计算的高度(递归) int height(TreeNode* root) { if (root == NULL) return 0; int leftHeight = height(root->left); int rightHeight = height(root->right); return (leftHeight > rightHeight ? leftHeight : rightHeight) + 1; } // 判断平衡二叉树的主函数(递归) bool isBalanced(TreeNode* root) { if (root == NULL) return true; // 空是平衡的 // 计算左右子高度差 int diff = abs(height(root->left) - height(root->right)); // 检查当前节点和递归检查子 return (diff <= 1) && isBalanced(root->left) && isBalanced(root->right); } // 辅助函数:创建新节点 TreeNode* createNode(int data) { TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode)); newNode->data = data; newNode->left = newNode->right = NULL; return newNode; } int main() { /* 测试用例:构建示例二叉 1 / \ 2 3 / \ \ 4 5 6 */ TreeNode* root = createNode(1); root->left = createNode(2); root->right = createNode(3); root->left->left = createNode(4); root->left->right = createNode(5); root->right->right = createNode(6); // 判断并输出结果 if (isBalanced(root)) printf("该二叉平衡二叉树\n"); else printf("该二叉不是平衡二叉树\n"); /* 释放内存(实际应用中需实现完整的内存管理)*/ return 0; } ``` #### 代码解析: 1. **数据结构**: - `TreeNode`结构体包含节点数据和左右子指针[^1][^4] 2. **核心函数**: - `height()`:递归计算的高度(时间复杂度$O(n)$) - `isBalanced()`:判断平衡性的主函数 - 检查当前节点左右子高度差$|h_{left} - h_{right}| \leq 1$ - 递归检查左右子是否平衡 3. **算法特点**: - 时间复杂度:$O(n^2)$(最坏情况) - 空间复杂度:$O(h)$($h$为高,递归栈空间)[^2] - 自顶向下递归:符合平衡二叉树的递归定义 #### 优化方向: 对于大规模,可优化为自底向上递归(时间复杂度$O(n)$): ```c int checkHeight(TreeNode* root) { if (!root) return 0; int leftHeight = checkHeight(root->left); if (leftHeight == -1) return -1; int rightHeight = checkHeight(root->right); if (rightHeight == -1) return -1; if (abs(leftHeight - rightHeight) > 1) return -1; return (leftHeight > rightHeight ? leftHeight : rightHeight) + 1; } bool isBalancedOptimized(TreeNode* root) { return checkHeight(root) != -1; } ``` #### 测试用例设计建议: 1. 空(平衡) 2. 单节点(平衡) 3. 完全平衡树(平衡) 4. 左/右斜(不平衡) 5. 最小不平衡子(如[1,2,3,4]线性) > 注意:实际应用中需添加内存管理代码防止泄漏[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值