算法-树(2)—2-3树,红黑树

本篇文章主要介绍2-3树,并由2-3树重点介绍RB树(红黑树)

后附完整代码

2-3树

1. 2-3树

2-3树概念:

一颗2-3查找树,或为空树,或为由2-结点,3-结点构成的树。

2-结点:含有一个键值对和两个链接,左链接的结点均小于该结点,右链接的结点均大于该结点。

3-结点:含有两个键值对和三个链接,左链接的结点小于该节点的小的键值,中链接介于该结点的两个键值之间,右链接大于改结点的大的键值。

2. 2-3树的查找添加

1).查找:

参照上一篇文章,实现较为简单,即比较需要查找的key值和x.left,x.right比较,递归实现。

2).添加:

添加首先需要查找添加到的正确位置;

然后主要两类(其他都可以由这两个变换出):

一:添加到空结点—直接添加,或者向2-结点添加(2-结点变为3-结点实现);

二:向3-结点的树增加新键值,1.创建一个4-结点,2.将4-结点分解为两个2-结点树;

<如向一个父结点为3-结点的3-结点添加新键值,同样先变为4-结点,再递归往上变为3-结点,若递归到跟结点仍为4-结点,则直接分解根结点>

红黑树

1.红黑树定义

基本思想:

用标准的二叉查找树(全部由2-结点组成)和一些额外信息(颜色:红黑)表示的2-3树。

其中,其满足以下三个含有红黑链的二叉查找树:

1>红链接均为做链接;

2>没有任何一个结点是同时由两个红链接组成;

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

红黑树的添加操作

为什么会有红黑树的旋转操作?为什么会有左右链接和颜色转换?

因为必须保证树是完美黑色平衡的。

所以在涉及红黑树的操作,如增加时:

我们必须保证刚刚增加的结点的链接颜色是红色的。(这样递归增加这样的结点时候,树就是红黑树了)

假如我们刚刚增加的结点是大于根结点的,这个时候就需要用到左旋转了。

而右旋转则是因为存在两条连续的红色做链接,所以这时候需要右旋转后再左旋转。

* 红黑树的旋转*

1).结点内部类定义:

    private class Node
    {
        private int N;
        private Node left,right;
        private Key key;
        private Value val;
        boolean color;
        public Node(Key key,Value val,int N,boolean color)
        {
            this.key = key;
            this.val = val;
            this.N = N;
            this.color = color;
        }
    }

2).左旋转:

存在右边链接为红色的结点。

实现如下:

    private Node rotateLeft(Node h)
    {
        Node x = h.right;
        h.right = x.left;
        x.left = h;
        x.color = h.color;
        h.color = RED;
        x.N = h.N;
        h.N = size(h.left) + size(h.right)+1;
        return x;
    }

3).右旋转:

存在两条连续的左链接为红色。

如:x.left = RED && x.left.left = RED;

实现:

    private Node rotateRight(Node h)
    {
        Node x = h.left;
        h.left = x.right;
        x.right = h;
        x.color = h.color;
        h.color = RED;
        x.N = h.N;
        h.N = size(h.left) + size(h.right)+1;
        return x;
    }

4).颜色转换

    //此函数是copy网站的,原本实现需要创建两个类似函数
    //一个是用于put添加操作:将结点变为红色(因为两个链接为红链接)
    //一个用于删除操作:将结点变为黑色,两个链接变为红色.
    // flip the colors of a node and its two children
    private void flipColors(Node h) {
        // h must have opposite color of its two children
        // assert (h != null) && (h.left != null) && (h.right != null);
        // assert (!isRed(h) &&  isRed(h.left) &&  isRed(h.right))
        //    || (isRed(h)  && !isRed(h.left) && !isRed(h.right));
        h.color = !h.color;
        h.left.color = !h.left.color;
        h.right.color = !h.right.color;
    }

添加操作put实现:

    private Node put(Node h, Key key, Value val)
     {
        //Recursive comparison the node insertion location
        //添加的结点,显然是要设置为红色的
        if (h == null)
            return new Node(key, val, 1, RED);

        int cmp = key.compareTo(h.key);
        if      (cmp < 0)
            h.left  = put(h.left,  key, val);
        else if (cmp > 0)
            h.right = put(h.right, key, val);
        else
            h.val   = val;

        //每一次递归增加元素,都需要修复红黑树,以保证三个定义.
        // fix-up any right-leaning links
        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.N = size(h.left) + size(h.right) + 1;

        return h;
    }

红黑树删除操作

删除操作时,我们必须保证删除的不是2-结点,因为2-结点删除后悔形成一个空链接,从而破坏了红黑树的第三个定义。

1. 2-3-4树的插入算法

<此算法实现沿路径既能向上也能向下进行变换的操作>

分为两部分:

1>向下变换

保证当前结点不是4-结点,当遇到父结点为2-结点的4-结点,将4-结点分为两个2-结点,并且将中间键值传给父结点(父结点变为3-结点); 当遇到父结点为3-结点的4-结点,同样将上一操作(此时父结点变为4-结点——用向上变换摊平)。

2>向上变换

之前创建的4-结点配平(分解为三个2-结点,高度增加1)。

此算法在红黑树上的实现:

1>将4-结点分解为三个2-结点子树,用红链接连接起来;

2>向下过程(递归过程)将所有4-结点进行颜色转换;

3>向上过程,分解旋转分解所有4-结点(配平)。

2. 删除最小键

由红黑书的第三个定义可以知道,删除键时,假如删除的是2-结点,会形成一个空链接,从而导致第三个定义不符合。因此,删除红黑树键时,当前结点必须是3-结点或者是4-结点。

完成以上要求的,必须满足一下情况之一:

1>假如当前结点不是2-结点;

2>当前结点的左子结点是2-结点,而当前结点的兄弟结点不是2-结点,此时需要借一个结点进行删除操作;

3>以上两个条件均不符合时,则将父结点和与当前结点相邻的结点合并为3-结点或者4-结点。

三个过程如下图:

实现如下:

    public void deleteMin()
    {
        if(!isRed(root.left) && !isRed(root.right))
            root.color = RED;
        root = deleteMin(root);
        if(isEmpty())
            root.color = BLACK;
    }

    private Node deleteMin(Node h)
    {
        if(h.left == null)
            return null;
        if(!isRed(h.left) && !isRed(h.left.left))
            h = moveRedLeft(h);  //因为是删除最小值操作,所以若删除的是黑链接,形成的空链接必定破坏平衡性.
        h.left = deleteMin(h.left);

        return balance(h);
    }

其中moveRedLeft(删除的结点是红色)如下:

    private Node moveRedLeft(Node h)
    {
        flipColors(h);
        if(isRed(h.right.left))
        {
            //红链接往右移动,这样就保证了删除最小值h.right.left后,仍然是黑色平衡
            h.right = rotateRight(h.right);
            //而上一部的操作,可能会让h.right结点为红色,所以修复
            h = rotateLeft(h);
        }
        return h;
    }

其中banlance函数(删除后,修复红黑树)实现如下:

    private Node balance(Node h)
    {
        if(isRed(h.right))
            h = rotateLeft(h);
        if(isRed(h.left) && isRed(h.left.left))
            h = rotateRight(h);
        if(isRed(h.right) && !isRed(h.left))
            h = rotateLeft(h);
        if(isRed(h.left) && isRed(h.right))
            flipColors(h);

        h.N = size(h.left)+size(h.right)+1;
        return h;
    }

3. 删除任意键

与删除最小键值类似,必须确保删除的结点不是2-结点.

1>当删除节点是位于底部时,可以直接删除;不是底部,则和上一篇文章,删除二叉搜索树的结点类似。

2>删除后,仍需使用回溯并分解剩余的4-结点。

实现:

 public void delete(Key key) {
        if (!(get(key) != null)) return;
        if (!isRed(root.left) && !isRed(root.right))
            root.color = RED;
        root = delete(root, key);
        if (!isEmpty()) root.color = BLACK;
    }
    private Node delete(Node h, Key key) {
        if (key.compareTo(h.key) < 0)  {
            if (!isRed(h.left) && !isRed(h.left.left))
                h = moveRedLeft(h);
            h.left = delete(h.left, key);
        }
        else {
            if (isRed(h.left))
                h = rotateRight(h);
            if (key.compareTo(h.key) == 0 && (h.right == null))
                return null;
            if (!isRed(h.right) && !isRed(h.right.left))
                h = moveRedRight(h);
            if (key.compareTo(h.key) == 0) {
                Node x = min(h.right);
                h.key = x.key;
                h.val = x.val;
                h.right = deleteMin(h.right);
            }
            else h.right = delete(h.right, key);
        }
        return balance(h);
    }
参照网站:http://algs4.cs.princeton.edu/30searching/

算法第四版

时间: 2024-08-28 23:25:43

算法-树(2)—2-3树,红黑树的相关文章

查找算法总结(二分查找/二叉查找树/红黑树/散列表)

1.二分查找 二分查找时,先将被查找的键和子数组的中间键比较.如果被查找的键小于中间键,就在左子数组继续查找,如果大于中间键,就在右子数组中查找,否则中间键就是要找的元素. /** * 二分查找 */ public class BinarySearch { public static int find(int[] array, int key) { int left = 0; int right = array.length - 1; // while (left <= right)不能改为<

程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大系列集锦

程序员面试.算法研究.编程艺术.红黑树.数据挖掘5大系列集锦

二叉树、平衡二叉树、B树、B+数、红黑树(简述)

二叉查找树(BST)具备什么特性呢?1.左子树上所有结点的值均小于或等于它的根结点的值.2.右子树上所有结点的值均大于或等于它的根结点的值.3.左.右子树也分别为二叉排序树.查找结点里面的值 的方式就是二分查找的思想 查找次数就是树的高度 二叉查找树可以任意地构造 向一方倾斜的二叉树是不平衡的,查询效率就低了 平衡二叉树(AVL Tree):插入或删除一个节点后,AVL树失去平衡,AVL树失去平衡之后,可以通过旋转使其恢复平衡将根节点的左或右孩子作为新根节点(左旋 右旋 多次旋) 平衡多路查找树

算法导论 第十三章:红黑树

红黑树(red-black tree)是一种"平衡"查找树,它能保证最坏情况下,基本的动态集操作时间为O(lgn). 性质: 1)每个节点要么是红的,要么是黑的 2)根节点和叶子节点(NIL)是黑色的 3)若一个节点是红色的,则他的两个孩子节点是黑色的 4)对于每一个节点x,从该节点到其子酸节点的所有路径上包含相同数目的黑节点(#black nodes = black-height(x)) 引理: 一棵有n个内节点的红黑树的高度至多为 2 lg(n+1) 红黑树上插入删除的完整代码如下

红黑树和AVL树的实现与比较-----算法导论

一.问题描述 实现3种树中的两种:红黑树,AVL树,Treap树 二.算法原理 (1)红黑树 红黑树是一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是red或black.红黑树满足以下五个性质: 1) 每个结点或是红色或是黑色 2) 根结点是黑色 3) 每个叶结点是黑的 4)如果一个结点是红的,则它的两个儿子均是黑色 5) 每个结点到其子孙结点的所有路径上包含相同数目的黑色结点 本实验主要实现红黑树的初始化,插入和删除操作.当对红黑树进行插入和 删除操作时,可能会破坏红黑树的五

浅谈算法和数据结构: 九 平衡查找树之红黑树

原文:浅谈算法和数据结构: 九 平衡查找树之红黑树 前面一篇文章介绍了2-3查找树,可以看到,2-3查找树能保证在插入元素之后能保持树的平衡状态,最坏情况下即所有的子节点都是2-node,树的高度为lgN,从而保证了最坏情况下的时间复杂度.但是2-3树实现起来比较复杂,本文介绍一种简单实现2-3树的数据结构,即红黑树(Red-Black Tree) 定义 红黑树的主要是像是对2-3查找树进行编码,尤其是对2-3查找树中的3-nodes节点添加额外的信息.红黑树中将节点之间的链接分为两种不同类型,

【算法导论学习-26】 二叉树专题4:红黑树、AVL树、B-Tree

1.   红黑树(Red-Black Trees) 参考<算法导论>P308页,红黑树是一种对树的高度要求最灵活的准平衡二叉搜索树.五大属性: 1: Every node is either RED or BLACK. 2: The root is black. 3: Every leaf(NIL) is black.  (The NIL is the sentinel.) 4: If a node is RED, then both its children areblack. 5: For

浅谈算法和数据结构: 七 二叉查找树 八 平衡查找树之2-3树 九 平衡查找树之红黑树 十 平衡查找树之B树

http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html 前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的时候具有较高的灵活性,而有序数组在查找时具有较高的效率,本文介绍的二叉查找树(Binary Search Tree,BST)这一数据结构综合了以上两种数据结构的优点. 二叉查找树具有很高的灵活性,对其优化可以生成平衡二叉树,红黑树等高效的查找和插入数据结构,后文会一一介绍. 一 定义 二叉查找树(B

【转】浅谈算法和数据结构: 九 平衡查找树之红黑树

http://www.cnblogs.com/yangecnu/p/3627386.html 前面一篇文章介绍了2-3查找树,可以看到,2-3查找树能保证在插入元素之后能保持树的平衡状态,最坏情况下即所有的子节点都是2-node,树的高度为lgN,从而保证了最坏情况下的时间复杂度.但是2-3树实现起来比较复杂,本文介绍一种简单实现2-3树的数据结构,即红黑树(Red-Black Tree) 定义 红黑树的主要是像是对2-3查找树进行编码,尤其是对2-3查找树中的3-nodes节点添加额外的信息.

数据结构(三):非线性逻辑结构-特殊的二叉树结构:堆、哈夫曼树、二叉搜索树、平衡二叉搜索树、红黑树、线索二叉树

在上一篇数据结构的博文<数据结构(三):非线性逻辑结构-二叉树>中已经对二叉树的概念.遍历等基本的概念和操作进行了介绍.本篇博文主要介绍几个特殊的二叉树,堆.哈夫曼树.二叉搜索树.平衡二叉搜索树.红黑树.线索二叉树,它们在解决实际问题中有着非常重要的应用.本文主要从概念和一些基本操作上进行分类和总结. 一.概念总揽 (1) 堆 堆(heap order)是一种特殊的表,如果将它看做是一颗完全二叉树的层次序列,那么它具有如下的性质:每个节点的值都不大于其孩子的值,或每个节点的值都不小于其孩子的值