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


定义:平衡二叉树(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.csdn.net/qq_34992845/article/details/75041981

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值