3.3 平衡查找树

希望找到一种数据结构,能够保证所有操作(范围查找除外)均能够在对数时间内完成操作,以便改变二叉查找树的不足。

平衡查找树Balance Search Tree

一.2-3查找树

1.数据结构:每个结点允许1个或者两个key

(1)2-node:一个键,两个child。左子树小于该节点,右子树大于该节点。

(2)3-node:两个键,三个child。左子树小于两个节点,右子树大于两个节点,中间的子树在两个节点之间。

这个限定称为symmetric order

2.完美平衡(Perfect balance):所有空链接到根结点的距离应该相等。

3.查找的思路:根据2-3查找树的概念,从根开始递归的查找该元素。和二叉查找树类似。

4.插入的思路:(保持完美平衡和symmetric order)

(1)如果在底部的2-node中插入,查找key应该插入的位置,然后将2-node变为3-node

(2)如果在底部的3-node中插入

  1)在3-node中增加一个key,暂时形成4-node

  2)将4-node中中间的一个移动到父结点中

  3)如果不满足2-3的结构的话,重复上面的过程

  4)如果已经到达了根结点,并且根结点是一个4-node,则将它拆分为3个2-node,也就是使得树的层次+1

5.三种情况举例:

(1)插入K(2-node变为3-node)

-------------》

(2)插入Z(临时4-node移动到父结点)

--------------------》

(3)插入L(根结点都满了,增加树的高度)

--------》------》

6.说明:

(1)树的高度。最坏的情况,全为2-nodes,性能是lgN。最好的情况,全为3-nodes,性能是logN/log3。

(2)对于million结点来说,树的高度在12到20之间。对于billion结点来说,高度在18到30之间。

(3)可以保证clgN的性能。

(4)直接的实现很复杂

二.红黑二叉查找树red-black BSTs

1.基本思想:利用标准的二叉查找树和一些额外的信息来表示2-3树

(1)红链接将2-node连接起来构成3-node

(2)黑链接则是2-3树中的普通链接

(3)3-node中较大的key是root

2.另一个等价的定义:红黑树(left-leaning red-black BST)是一个含有红黑链接的特殊的二叉查找树,满足:

(1)没有一个结点同时和两个红链接相连

(2)该树是完美黑色平衡。即任意空链接到根结点的路径上的黑链接数量相同

(3)红链接均为链接。

3.从上面的分析可以,红黑树是 2-3树的一种等价的简单的实现。

4.查找。和普通的BST类似(不考虑颜色),但是由于具有更好的平衡性,红黑树有更快的查找速度。

   很多其他的操作(ceiling,selection等),也和普通的BST类似。

5.用BST表示红黑树。颜色表示,在普通BST的实现中给每个Node加上一个颜色(布尔值),表示父链接的颜色是红(true)/黑(false)。

6.左旋转。将一个右倾斜的红链接变为左倾斜。依旧维持了symmetric order和完美黑色平衡。

--------------------》

    //左旋转,将右倾斜变为左倾斜
    Node rotateLeft(Node h) {
        //结点关系
        Node x=h.right;
        h.right=x.left;
        x.left=h;
        //颜色
        x.color=h.color;
        h.color=RED;
        return x;    
    }
View Code

7.右旋转。作为过渡的步骤。

---------------》

    //右旋转
    Node rotateRight(Node h) {
        Node x=h.left;
        h.left=x.right;
        x.right=h;
        x.color=h.color;
        h.color=RED;
        return x;
    }
View Code

8.颜色反转。重绘颜色来分开一个临时的4-node。

----------------》

    private void flipColors(Node h) {
        h.color=RED;
        h.left.color=BLACK;
        h.right.color=BLACK;
    }
View Code

9.插入。通过上述基本操作可以使得2-3树和红黑树一一对应。

向一个3-node中插入新键的三种情况(算法的基础)

10.例子(完整的例子见算法P282)

---》-->-->-->

11.插入的思路:(以下结论对上述讨论的所有情况均满足)

(1)右边child是红色,左边child是黑色:左旋转

(2)左边child,左左边grandchild均为红色:右旋转

(3)children均是红色:颜色反转

12.插入操作的代码实现

package com.cx.serch;

public class RedBlackBST <Key extends Comparable<Key>,Value>{
    private Node root;
    private static final boolean RED=true;
    private static final boolean BLACK=false;
    private class Node{
        Key key;
        Value value;
        Node left,right;
        int count;
        //父链接的颜色
        boolean color;
        public Node(Key key,Value value,int count,boolean color) {
            this.key=key;
            this.value=value;
            this.count=count;
            this.color=color;
        }
    }
    /**
     *    实现size()方法
     */
    public int size() {
        return size(root);
    }
    private int size(Node x) {
        if(x==null) return 0;
        return x.count;
    }
    /**
     *    实现put()方法
     */
    public void put(Key key,Value value) {
        root=put(root, key, value);
        root.color=BLACK;
    }
    //插入元素操作
    private Node put(Node h,Key key,Value value) {
        //在底层插入时,先插入红链接
        if(h==null) return new Node(key,value,1,RED);
        //普通BST的插入操作
        int cmp=key.compareTo(h.key);
        if(cmp<0) h.left=put(h.left, key, value);
        else if(cmp>0) h.right=put(h.right, key, value);
        else h.value=value;
        
        //右子结点是红色,左子结点是黑色,进行左旋转
        if(isRed(h.right) && !isRed(h.left)) h=rotateLeft(h);
        //左子结点和左左子结点为红,右旋转
        if(isRed(h.left) && isRed(h.left.left)) h=rotateRight(h);
        //左右子结点均为红色,颜色转换
        if(isRed(h.left) && isRed(h.right)) flipColors(h);
    
        h.count=1+size(h.left)+size(h.right);
        return h;
    }
    
    private boolean isRed(Node x) {
        if(x==null) return false;
        return x.color==RED;
    }
    
    //左旋转,将右倾斜变为左倾斜
    Node rotateLeft(Node h) {
        //结点关系
        Node x=h.right;
        h.right=x.left;
        x.left=h;
        //颜色
        x.color=h.color;
        h.color=RED;
        return x;    
    }
    //右旋转
    Node rotateRight(Node h) {
        Node x=h.left;
        h.left=x.right;
        x.right=h;
        x.color=h.color;
        h.color=RED;
        return x;
    }
    //反转颜色
    private void flipColors(Node h) {
        h.color=RED;
        h.left.color=BLACK;
        h.right.color=BLACK;
    }
    
}
View Code

13.说明

(1)红黑树在最坏情况下,树的高度不大于2lgN

(2)在应用中,红黑树的盖度~1.00lgN

(3)具有lgN的性能保障

14.红黑树的用途:

(1)Java:java.util.TreeMap,java.util.TreeSet

(2)C++ STL:map,multimap,mulyiset

(3)Linux内核:完全公平调度 

 三.B树

1.用在数据量较大,外存占主要部分时,B树因其读磁盘次数少,而具有更快的速度。

2.类似2-3树,但是我们允许每个结点有更多的keys,当结点满的时候,会分解为2个,所以每个结点都在半满和满之间。

3.在B树中插入或查找m阶N个键需要

  实际中,M=1024,N=62billion,则最多为4次探索磁盘

4.B树用途:数据库:sql、Oracle、DB2

原文地址:https://www.cnblogs.com/sunnyCx/p/8243097.html