(四)平衡二叉树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jiangshangchunjiezi/article/details/88540465

一、二叉排序树的缺点

若树中插入的是随机数据,则执行效果很好,但是若插入的是有序或者是逆序的数据,则二叉查找树的执行速度很慢。

为了能以较快的时间 O(logN) 来搜索一棵树,需要保证树总是平衡的(或者至少大部分是平衡的),这就是说对树中的每个节点在它左边的后代数目和在它右边的后代数目应该大致相等。红-黑树的就是这样的一棵平衡树,对一个要插入的数据项,插入例程要检查会不会破坏树的特征,如果破坏了,程序就会进行纠正,根据需要改变树的结构,从而保持树的平衡
 

二、简单介绍红黑树

a.红黑树是一种自平衡二叉查找树

b.java集合中的TreeSet、TreeMap都是通过红黑树去实现的

Q1:为什么TreeSet、TreeMap不用其他平衡树,比如AVL
答:虽然红黑树的操作复杂度和AVL是相同的,但是红黑树从不平衡调整为平衡所需的操作更少,统计性能更优

Q2:TreeSet和HashSet的比较
答:
①TreeSet是用红黑树实现的,操作复杂度为O(log2n),HashSet采用哈希+拉链去冲突,平均操作复杂度为O(1),所以一般查找HashSet更快

②TreeSet是红黑树,本质是一棵二叉排序树,元素是排好序的,同时也需要实现Comparator接口,实现compare方法。
HashSet需要重写hashCode()、equals()方法
③HashSet可以放null,但只能放一个。TreeSet不能放null(因为TreeSet需要排序,不能和null进行排序)

c.红黑树的各项操作(插、删、找),都是O(log2n)

d.红黑树性质(特征)

1、每个结点或是红色的,或是黑色的 
2、根节点是黑色的 
3、每个叶结点(NIL)是黑色的 (2、3简记为最上面和最下面是黑的)
4、如果一个节点是红色的,则它的两个儿子都是黑色的。 (反之不一定)
5、对于每个结点,从该结点到其叶子结点构成的所有路径上的黑结点个数相同。

三、和AVL树比较

AVL树是一棵严格的平衡树,它所有的子树都满足二叉平衡树的定义。树高严格限定,所以AVL查找效率比较高。但是AVL树插入、删除节点后旋转的次数比红黑树多

所以红黑树用非严格的平衡来降低插入、删除时的旋转次数

所以选用哪种,要看业务场景:

若查找多于插入、删除,则选AVL

若查找、插入、删除频率差不多,则选则红黑树

四、和二叉查找树比较

红黑树查找效率:O(log2n)

二叉查找树最坏查找O(N)

五、红黑树的数据结构

enum Color  
{  
          RED = 0,  
          BLACK = 1  
};  
  
struct RBTreeNode  
{  
           struct RBTreeNode*left, *right, *parent;  
           int   key;  
           int data;  
           Color color;  
};

六、红黑树相对于哈希表,在选择使用的时候有什么依据

权衡三个因素: 查找速度, 数据量, 内存使用,可扩展性。
  总体来说,hash查找速度会比map快,而且查找速度基本和数据量大小无关,属于常数级别;而map的查找速度是log(n)级别。并不一定常数就比log(n) 小,hash还有hash函数的耗时,明白了吧,如果你考虑效率,特别是在元素达到一定数量级时,考虑考虑hash。但若你对内存使用特别严格, 希望程序尽可能少消耗内存,那么一定要小心,hash可能会让你陷入尴尬,特别是当你的hash对象特别多时,你就更无法控制了,而且 hash的构造速度较慢。

红黑树并不适应所有应用树的领域。如果数据基本上是静态的,那么让他们待在他们能够插入,并且不影响平衡的地方会具有更好的性能。如果数据完全是静态的,例如,做一个哈希表,性能可能会更好一些。

在实际的系统中,例如,需要使用动态规则的防火墙系统,使用红黑树而不是散列表被实践证明具有更好的伸缩性。Linux内核在管理vm_area_struct时就是采用了红黑树来维护内存块的。

红黑树通过扩展节点域可以在不改变时间复杂度的情况下得到结点的秩。

猜你喜欢

转载自blog.csdn.net/jiangshangchunjiezi/article/details/88540465