算法5-2:红黑树

红黑树就是将二三树表示成二叉树的形式,极大地简化了算法。

红黑树的基本思想就是将二三树中的三节点表示成两个二节点,而这两个二节点之间使用红色的连接,普通连接使用黑色的连接。

红黑树中的每个节点都有以下性质:

  • 没有一个节点同时拥有两个红连接
  • 每个空节点到根节点路径上黑色连接的数量都是相同的
  • 红连接只会出现在左边

下图展示了二三树和红黑树的等价表示

查找操作

与普通的二叉树查找树的算法一致,忽略节点的颜色即可。

旋转操作

有时候会出现下图红连接在右侧的情况。这时候就需要通过左旋操作,使其符合红黑树的性质。

下图展示了旋转之后的样子

代码如下:

private Node rotateLeft(Node node) {
    Node right = node.right;
    node.right = right.left;
    right.left = node;
    int color = right.color;
    right.color = node.color;
    node.color = color;
    return right;
}

有时候也会用到右旋操作。右旋操作的目的是为了方便某些操作,等操作结束之后再通过左旋恢复原样。

翻转操作

有时候会出现下图这种双重红连接的情况,这种情况对应的就是二三树中的四节点。此时之需要改变父节点的颜色即可。这种操作叫做翻转操作。

下图是变化之后的图

代码如下:

private Node flipColor(Node node) {
    node.color = RED;
    node.left.color = BLACK;
    node.right.color = BLACK;
    return node;
}

插入操作

在红黑树中进行插入操作时,与普通的二叉查找树一样。每次新增一个子节点时,需要将新增的节点标记成红色。再通过旋转、翻转操作,维持红黑树的性质。

每次插入之后,需要执行以下步骤:

  • 如果右子节点是红色的,左子节点是黑色的,执行左旋操作
  • 如果左子节点和它的子节点都是红的,执行右旋操作
  • 如果两个子节点都是红色的,执行翻转操作

代码如下:

private Node put(Node node, Key key, Value value) {
    // 创建一个新的红色的节点
    if(node == null) {
        return new Node(key, value, RED);
    }

    // 定位到需要插入的节点
    int compare = key.compareTo(node.key);
    if(compare < 0) {
        node.left = put(node.left, key, value);
    } else if(compare > 0) {
        node.right = put(node.right, key, value);
    } else {
        node.value = node.value;
        return node;
    }

    // 调整红黑树,使其平衡
    if(isRed(node.right) && !isRed(node.left)) {
        return rotateLeft(node);
    }
    if(isRed(node.left) && isRed(node.left.left)) {
        return rotateRight(node);
    }
    if(isRed(node.left) && isRed(node.right)) {
        return flipColor(node);
    }

    return node;
}

性能

红黑树的插入、查找、删除操作的复杂度均为logN。

完整代码

public class RedBlackTree<Key extends Comparable<Key>, Value> {
    private static final int RED = 1;
    private static final int BLACK = 0;

    private class Node {
        Key key;
        Value value;
        Node left;
        Node right;
        int color;

        Node(Key key, Value value, int color) {
            this.key = key;
            this.value = value;
            this.color = color;
        }
    }

    private Node root;

    public void insert(Key key, Value value) {
        root = put(root, key, value);
    }

    private Node put(Node node, Key key, Value value) {
        // 创建一个新的红色的节点
        if(node == null) {
            return new Node(key, value, RED);
        }

        // 定位到需要插入的节点
        int compare = key.compareTo(node.key);
        if(compare < 0) {
            node.left = put(node.left, key, value);
        } else if(compare > 0) {
            node.right = put(node.right, key, value);
        } else {
            node.value = node.value;
            return node;
        }

        // 调整红黑树,使其平衡
        if(isRed(node.right) && !isRed(node.left)) {
            return rotateLeft(node);
        }
        if(isRed(node.left) && isRed(node.left.left)) {
            return rotateRight(node);
        }
        if(isRed(node.left) && isRed(node.right)) {
            return flipColor(node);
        }

        return node;
    }

    private boolean isRed(Node node) {
        // 空节点属于黑节点
        if(node == null) return false;

        // 判断节点是否为红色
        return node.color == RED;
    }

    private Node rotateLeft(Node node) {
        Node right = node.right;
        node.right = right.left;
        right.left = node;
        int color = right.color;
        right.color = node.color;
        node.color = color;
        return right;
    }

    private Node rotateRight(Node node) {
        Node left = node.left;
        node.left = left.right;
        left.right = node;
        int color = left.color;
        left.color = node.color;
        node.color = color;
        return left;
    }

    private Node flipColor(Node node) {
        node.color = RED;
        node.left.color = BLACK;
        node.right.color = BLACK;
        return node;
    }

    public Value get(Key key) {
        Node node = root;
        while(node != null) {
            int compare = key.compareTo(node.key);
            if(compare < 0) {
                node = node.left;
            } else if(compare > 0) {
                node = node.right;
            } else {
                return node.value;
            }
        }

        // 没有找到
        return null;
    }
}

算法5-2:红黑树

时间: 2024-10-06 23:54:18

算法5-2:红黑树的相关文章

算法导论学习---红黑树具体解释之插入(C语言实现)

前面我们学习二叉搜索树的时候发如今一些情况下其高度不是非常均匀,甚至有时候会退化成一条长链,所以我们引用一些"平衡"的二叉搜索树.红黑树就是一种"平衡"的二叉搜索树,它通过在每一个结点附加颜色位和路径上的一些约束条件能够保证在最坏的情况下基本动态集合操作的时间复杂度为O(nlgn).以下会总结红黑树的性质,然后分析红黑树的插入操作,并给出一份完整代码. 先给出红黑树的结点定义: #define RED 1 #define BLACK 0 ///红黑树结点定义,与普通

算法导论学习---红黑树详解之插入(C语言实现)

前面我们学习二叉搜索树的时候发现在一些情况下其高度不是很均匀,甚至有时候会退化成一条长链,所以我们引用一些"平衡"的二叉搜索树.红黑树就是一种"平衡"的二叉搜索树,它通过在每个结点附加颜色位和路径上的一些约束条件可以保证在最坏的情况下基本动态集合操作的时间复杂度为O(nlgn).下面会总结红黑树的性质,然后分析红黑树的插入操作,并给出一份完整代码. 先给出红黑树的结点定义: #define RED 1 #define BLACK 0 ///红黑树结点定义,与普通的二

算法导论 之 红黑树 - 插入[C语言]

作者:邹祁峰 邮箱:[email protected] 博客:http://blog.csdn.net/qifengzou 日期:2013.12.24 21:00 转载请注明来自"祁峰"的CSDN博客 1 引言 在之前的博文中,本人对平衡二叉树的处理做了较详尽的分析,有兴趣的朋友可以参阅博文<算法导论 之 平衡二叉树 - 创建 插入 搜索 销毁>和<算法导论 之 平衡二叉树 - 删除>.平衡二叉树AVL是严格的平衡树,在增删结点时,其旋转操作的次数较多:而红黑树

算法05 之红-黑树

从第4节的分析中可以看出,二叉搜索树是个很好的数据结构,可以快速地找到一个给定关键字的数据项,并且可以快速地插入和删除数据项.但是二叉搜索树有个很麻烦的问题,如果树中插入的是随机数据,则执行效果很好,但如果插入的是有序或者逆序的数据,那么二叉搜索树的执行速度就变得很慢.因为当插入数值有序时,二叉树就是非平衡的了,排在一条线上,其实就变成了一个链表--它的快速查找.插入和删除指定数据项的能力就丧失了. 为了能以较快的时间O(logN)来搜索一棵树,需要保证树总是平衡的(或者至少大部分是平衡的),这

【算法导论】红黑树详解之一(插入)

本文地址:http://blog.csdn.net/cyp331203/article/details/42677833 作者:苦_咖啡 欢迎转载,但转载请注明出处,否则将追究相应责任,谢谢!. 红黑树是建立在二叉查找树的基础之上的,关于二叉查找树可以参看[算法导论]二叉搜索树的插入和删除和[算法导论]二叉树的前中后序非递归遍历实现.对于高度为h的二叉查找树而言,它的SEARCH.INSERT.DELETE.MINIMUM.MAXIMUM等操作的时间复杂度均为O(h).所以在二叉查找树的高度较高

java数据结构和算法06(红黑树)

这一篇我们来看看红黑树,首先说一下我啃红黑树的一点想法,刚开始的时候比较蒙,what?这到底是什么鬼啊?还有这种操作?有好久的时间我都缓不过来,直到我玩了两把王者之后回头一看,好像有点儿意思,所以有的时候碰到一个问题困扰了很久可以先让自己的头脑放松一下,哈哈! 不瞎扯咳,开始今天的正题: 前提:看红黑树之前一定要先会搜索二叉树 1.红黑树的概念 红黑树到底是个什么鬼呢?我最开始也在想这个问题,你说前面的搜索二叉树多牛,各种操作效率也不错,用起来很爽啊,为什么突然又冒出来了红黑树啊? 确实,搜索二

算法导论之红黑树的学习

最近学习了二叉搜索树中的红黑树,感觉收获颇丰,在此写一篇文章小结一下学到的知识,顺便手写一下Java代码. 1.引言 先来讲讲什么是二叉搜索树,二叉搜索树有如下特点:他是以一颗二叉树(最多有两个子结点)来组织的,对于树中的某个节点,其左子树的所有元素均小于该节点,其右子树的元素均大于该节点.我们知道一颗有N个节点的二叉树的高度至少为lgN,然后在树上的操作都与其高度有关,因此限制树的高度就显得非常有必要.当一个二叉搜索树的高度是lgN时,在该树上的插入删除搜索等操作均为O(lgN)的时间复杂度,

java数据结构和算法-----第九章红黑树

平衡树和非平衡树 如果待插入的关键字是升序的或者降序的,将会产生非平衡树.(都只在根节点的左边或者右边) 当树没有分支时,此时的树就可以看做单链表.

浅析红黑树算法

红黑树简介 红黑树是一种自平衡二叉查找树,也有着二叉搜索树的特性,保持着右边始终大于左边结点key的特性.前面提到过的AVL树,也是二叉搜索树的一种变形,红黑树没有达到AVL树的高度平衡,换句话说,它的高度,并没有AVL树那么高的要求,但他的应用却更加的广泛,实践中是相当高效的,他可以在O(log n)的时间内做查找.插入.删除操作.在C++ STL中,set.multiset.map.multimap等都应用到的红黑树的变体. 红黑树在平衡二叉搜索树的前提下,每个节点新增了 _color 这一