内容:
1、搜索二叉树
2、典型搜索二叉树原理(AVL树、红黑树、SB树)
3、Java中红黑树的使用
1、搜索二叉树
搜索二叉树的定义:对于一棵二叉树中的任意子树,其左子树上的所有数值小于头结点的数值,
其右子树上所有的数值大于头结点的数值,并且树中不存在数值相同的结点。也称二叉查找树
如下图所示:
2、典型搜索二叉树原理(AVL树、红黑树、SB树)
(1)AVL树
平衡二叉树:对于一棵二叉树中的任意子树,其左子树和其右子树的 高度相差不超过1
AVL树是一种具有严苛平衡性的搜索二叉树,那就是所有子树的左子树和右子树的高度相差不超过1
弊端是,每次发现因为插入、删除操作破坏了这种平衡性后,都需作出调整从而恢复平衡,调整较为频繁
另外AVL树中插入、删除、调整的时间复杂度均是O(logN)
(2)红黑树
红黑树是每个节点都带有颜色属性的搜索二叉树,颜色或红色或黑色。
在搜索二叉树强制一般要求以外,对于任何 有效的红黑树我们增加了如下的额外要求:
- 性质1 节点是红色或黑色
- 性质2 根节点是黑色
- 性质3 每个叶节点(NIL节点,空节点)是黑色的
- 性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
- 性质5 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
这些约束强制了红黑树的关键性质: 从根到叶子的长的可能路径不多于短的可能路径的两倍长。结果是这个树
大致上是平衡的。因为操作比如插入、删除和查找某个值的坏情况时间都要求与树的高度成比例,这个在高度上
的理论上限允许红黑树在坏情况下都是高效的,而不同于普通的二叉查找树。
要知道为什么这些特性确保了这个结果,注意到性质4导致了路径不能有两个毗连的红色节点就足够了。
最短的可能路径都是黑色节点,长的可能路径有交替的红色和黑色节点。因为根据性质5所有长的路径都有
相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长
(3)SB树
相比红黑树、AVL树等自平衡二叉查找树,SB树更易于实现。SB树能在O(log n)的时间内完成所有二叉搜索树的相关操作
另外与普通二叉搜索树相比,SB树仅仅加入了简洁的核心操作Maintain
由于SB树赖以保持平衡的是size域而不是其他“无用”的域,它可以很方便地实现动态顺序统计中的select和rank操作
SB树的性质:对于数中任意结点,以该结点为根节点的子树的结点个数不能比以该结点的叔叔结点为根节点的子树的结点个数大。
注意:由于红黑树的实现较为复杂,因此现在工程中大多使用SB树作为平衡二叉树的实现
3、Java中红黑树的使用
Java中红黑树的实现有TreeSet和TreeMap ,前者结点存储的是单一数据,而后者存储的是 <key,value> 的形式
使用代码如下:
1 import java.util.Map; 2 import java.util.TreeMap; 3 4 public class useTreeMap { 5 public static void main(String[] args) { 6 TreeMap<Integer, String> treeMap = new TreeMap<Integer, String>(); 7 treeMap.put(new Integer(5), "Tom"); 8 treeMap.put(new Integer(11), "jack"); 9 treeMap.put(new Integer(30), "tony"); 10 treeMap.put(new Integer(18), "woz"); 11 treeMap.put(new Integer(25), "alice"); 12 13 // 红黑树中最右边的节点 14 System.out.println(treeMap.lastEntry()); 15 System.out.println(treeMap.lastKey()); 16 // 红黑树中最左边的节点 17 System.out.println(treeMap.firstKey()); 18 19 // 如果有13这个key,那么返回这条记录,否则返回树中比13大的key中小的那一个 20 System.out.println(treeMap.ceilingEntry(13)); 21 // 如果有21这个key,那么返回这条记录,否则返回树中比21小的key中大的那一个 22 System.out.println(treeMap.floorEntry(21)); 23 // 比11大的key中,小的那一个 24 System.out.println(treeMap.higherKey(11)); 25 // 比25小的key中,大的那一个 26 System.out.println(treeMap.lowerKey(25)); 27 // 遍历红黑树,是按key有序遍历的 28 for (Map.Entry<Integer, String> record : treeMap.entrySet()) { 29 System.out.println("age:" + record.getKey() + ",name:" 30 + record.getValue()); 31 } 32 33 } 34 }