红黑树的一个java实现

前几天闲来无事实现了一个红黑树,虽然感觉理解透了,但是真正写码的时候还是调了一个上午才调通,理论还是得联系实践才行啊。

另外可以看看234树,算是红黑树的一个变种,可以加深对红黑树的理解

红黑树性质

1)每个结点要么是红的,要么是黑的。

2)根结点是黑的。

3)每个叶结点,即空结点(NIL)是黑的。

4)如果一个结点是红的,那么它的俩个儿子都是黑的。

5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。

树的旋转

简单说就是把节点的一个子节点提上来当做主节点,原节点作为子节点

操作很简单,需要注意的一点就是树的深度的变化

插入节点

跟普通二叉树插入流程相似,只是需要多加一步平衡二叉树以满足红黑树的性质;

插入节点默认为红色,所以唯一可能破坏的性质为性质4)

大致可以按照下面的几种情况处理:

* 1. 如果父节点为黑色,平衡完成

* 2. 如果叔节点为红色,向上循环

* 3. 如果叔节点为黑色,把多余红色节点旋转到叔节点

删除节点

删除前面几步跟普通二叉树也一样,只删除节点后需要平衡二叉树

删除节点后会破坏性质5)

删除后补充节点

* 1. 如果只有一个孩子节点,直接提上孩子节点

* 2. 如果没有孩子节点,找到后继节点,将后继节点的值替换到删除节点,然后删除后继几点

平衡删除后的树也可以大致分为以下几种情况:

* 1. 如果补上来的节点为红色,直接变为黑色补足

* 2. 如果兄弟节点为黑色,侄子也为黑色,将兄弟变为红色;

*    与兄弟深度平衡后继续向上循环

* 3. 如果兄弟为红色,或者侄子为红色,抢夺一个红色的节点补足自身

具体代码

package com.feinno.algorithmic.tree;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
 *
 * @author renzhaolong
 *
 * @param <K>
 * @param <V>
 */
public class RedBlackTree<K extends Comparable<K>, V> {

    //哨兵节点
    private Node nil = new Node();
    //根节点
    private Node root = nil;

    /**
     * 插入新值
     * @param key
     * @param value
     */
    public void insert(K key, V value) {
        Node newNode = new Node(key, value);
        if (root == nil) {
            root = newNode;
            root.color = Color.Black;
            return;
        }
        Node currentNode = root;
        newNode.color = Color.Red;
        while (currentNode != nil) {
            int compare = key.compareTo(currentNode.key);
            if (compare >= 0) {
                if (currentNode.rightChild != nil) {
                    currentNode = currentNode.rightChild;
                } else {
                    currentNode.rightChild = newNode;
                    newNode.parent = currentNode;
                    break;
                }
            } else {
                if (currentNode.leftChild != nil) {
                    currentNode = currentNode.leftChild;
                } else {
                    currentNode.leftChild = newNode;
                    newNode.parent = currentNode;
                    break;
                }
            }
        }
        if (currentNode.color == Color.Red) {
            insertBalance(newNode);
        }
    }

    /**
     * 添加节点后平衡红黑树
     * 如果父节点为红色,两个连续红色节点
     * 1. 如果父节点为黑色,平衡完成
     * 2. 如果叔节点为红色,向上循环
     * 3. 如果叔节点为黑色,把多余红色节点旋转到叔节点
     * @param node
     */
    private void insertBalance(Node node) {
        Node parent = node.parent;
        //如果父节点同为红色,违反红黑树性质
        while (node != root && node.parent != root && parent.color == Color.Red) {
            //if left child
            if (parent.parent.leftChild == parent) {
                Node y = parent.parent.rightChild;
                //如果叔父节点也为红色,祖父节点已满,需要向上分裂
                if (y.color == Color.Red) {
                    parent.color = Color.Black;
                    y.color = Color.Black;
                    parent.parent.color = Color.Red;
                    node = parent.parent;
                    parent = node.parent;
                } else { //否则通过旋转维持平衡
                    //if right child
                    if (parent.rightChild == node) {
                        parent = leftRotate(parent);
                    }
                    parent.color = parent.parent.color;
                    parent.parent.color = Color.Red;
                    parent = rightRotate(parent.parent);
                    break;
                }
            } else {
                Node y = parent.parent.leftChild;
                if (y.color == Color.Red) {
                    parent.color = Color.Black;
                    y.color = Color.Black;
                    parent.parent.color = Color.Red;
                    node = parent.parent;
                    parent = node.parent;
                } else {
                    if (parent.leftChild == node) {
                        parent = rightRotate(parent);
                    }
                    parent.color = parent.parent.color;
                    parent.parent.color = Color.Red;
                    parent = leftRotate(parent.parent);
                    break;
                }
            }
        }
        root.color = Color.Black;
    }

    /**
     * 删除key所在node
     * 如果节点不是子节点,需要确定后补节点
     * 1. 如果只有一个孩子节点,直接提上孩子节点
     * 2. 如果没有孩子节点,找到后继节点,将后继节点的值替换到删除节点,然后删除后继几点
     * @param key
     */
    public V delete(K key) {
        Node del = search(key);
        if (nil == del) {
            return null;
        }
        V result = del.value;
        if (del.leftChild != nil && del.rightChild != nil) {
            Node successor = getSuccessorNode(del);
            del.key = successor.key;
            del.value = successor.value;
            del = successor;
        }
        Node current;
        if (del.leftChild != nil) {
            current = del.leftChild;
        } else {
            current = del.rightChild;
        }
        current.parent = del.parent;
        if (current.parent.leftChild == del) {
            current.parent.leftChild = current;
        } else {
            current.parent.rightChild = current;
        }
        //如果删除的是黑色节点,需要重新平衡
        if (del.color == Color.Black) {
            DeleteBalance(current);
        }

        return result;
    }

    /**
     * 删除节点后平衡红黑树
     * 删除节点的子树深度不够
     * 补足深度
     * 1. 如果节点为红色,直接变为黑色补足
     * 2. 如果兄弟节点为黑色,侄子也为黑色,将兄弟变为红色;
     *    与兄弟深度平衡后继续向上循环
     * 3. 如果兄弟为红色,或者侄子为红色,抢夺一个红色的节点补足自身
     * @param node
     */
    private void DeleteBalance(Node node) {
        while (node != root && node.color == Color.Black) {
            Node parent = node.parent;
            if (parent.leftChild == node) {
                Node right = parent.rightChild;
                if (right.color == Color.Red) {
                    right.color = Color.Black;
                    parent.color = Color.Red;
                    node = leftRotate(parent);
                    right = parent.rightChild;
                }
                if (right.leftChild.color == Color.Black &&
                        right.rightChild.color == Color.Black) {
                    right.color = Color.Red;
                    node = parent;
                    continue;
                } else {
                    if (right.rightChild.color == Color.Black) {
                        right.color = Color.Red;
                        right.leftChild.color = Color.Black;
                        right = rightRotate(right);
                    }
                    parent = leftRotate(parent);
                    parent.color = parent.leftChild.color;
                    parent.rightChild.color = Color.Black;
                    parent.leftChild.color = Color.Black;
                    break;
                }
            } else {
                Node left = parent.leftChild;
                if (left.color == Color.Red) {
                    left.color = Color.Black;
                    parent.color = Color.Red;
                    rightRotate(parent);
                    left = parent.leftChild;
                }
                if (left.leftChild.color == Color.Black &&
                        left.rightChild.color == Color.Black) {
                    left.color = Color.Red;
                    node = parent;
                    continue;
                } else {
                    if (left.leftChild.color == Color.Black) {
                        left.color = Color.Red;
                        left.rightChild.color = Color.Black;
                        left = leftRotate(left);
                    }
                    parent = rightRotate(parent);
                    parent.color = parent.rightChild.color;
                    parent.rightChild.color = Color.Black;;
                    parent.leftChild.color = Color.Black;
                    //node = parent;
                    break;
                }
            }
        }
        node.color = Color.Black;
    }

    /**
     * 获取当前节点的后继节点
     * @param node
     * @return
     */
    private Node getSuccessorNode(Node node) {
        if (node.rightChild == nil) {
            Node temp = node;
            while (temp.parent != nil) {
                if (temp.parent.leftChild == temp) {
                    return temp.parent;
                }
            }
            return nil;
        }
        if (node.rightChild != nil) {
            Node temp = node.rightChild;
            while (temp.leftChild != nil) {
                temp = temp.leftChild;
            }
            return temp;
        }
        return nil;
    }

    /**
     * 右旋
     * 把左子节点提上来
     * @param node
     * @return
     */
    private Node rightRotate(Node node) {
        Node left = node.leftChild;
        node.leftChild = left.rightChild;
        node.leftChild.parent = node;
        left.rightChild = node;
        left.parent = node.parent;
        node.parent = left;
        if (left.parent.leftChild == node) {
            left.parent.leftChild = left;
        } else {
            left.parent.rightChild = left;
        }
        return left;
    }

    /**
     * 左旋
     * 把右子节点提上来
     * @param node
     * @return
     */
    private Node leftRotate(Node node) {
        Node right = node.rightChild;
        node.rightChild = right.leftChild;
        node.rightChild.parent = node;
        right.leftChild = node;
        right.parent = node.parent;
        node.parent = right;
        if (right.parent.leftChild == node) {
            right.parent.leftChild = right;
        } else {
            right.parent.rightChild = right;
        }
        return right;
    }

    /**
     * 根据key获取value
     * @param key
     * @return
     */
    public V get(K key) {
        return search(key).value;
    }

    /**
     * 根据key查找Node
     * @param key
     * @return
     */
    private Node search(K key) {
        Node result = root;
        while (result != nil) {
            int compare = key.compareTo(result.key);
            if (compare == 0) {
                return result;
            } else if (compare > 0) {
                result = result.rightChild;
            } else {
                result = result.leftChild;
            }
        }
        return nil;
    }

    private boolean checkBalance() {
        if (root == nil) { return true; }
        if (root.color == Color.Red) { return false; }
        int height = getNodeHeight(root);
        if (-1 == height) {
            return false;
        }
        return true;
    }

    /**
     * 如果满足红黑树性质
     * 如果不满足,返回-1
     * @param node
     * @return
     */
    private int getNodeHeight(Node node) {
        if (node == nil) {
            return 0;
        }
        if (Color.Red == node.color && Color.Red == node.parent.color) {
            return -1;
        }
        int left = getNodeHeight(node.leftChild);
        if (-1 == left) {
            return -1;
        }
        int right = getNodeHeight(node.rightChild);
        if (left != right) {
            return -1;
        }
        if (Color.Red == node.color)
            return right;
        return right + 1;
    }

    private class Node implements Comparable<Node> {
        private Node parent = nil;
        private Node leftChild = nil;
        private Node rightChild = nil;
        private Color color = Color.Black;
        private K key;
        private V value;

        public Node(){}

        public Node(K key, V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public int compareTo(Node o) {
            return key.compareTo(o.key);
        }

        public String toString() {
            return "Key:" + key.toString() + " Color:" + color;
        }
    }
    private static enum Color {
        Red,
        Black
    }

    public static void main(String[] args) throws Exception {
        RedBlackTree<Integer, Integer> rb = new RedBlackTree<Integer, Integer>();
        List<Integer> keys = new LinkedList<Integer>();
        Random ran = new Random();

        for (int i = 0; i < 1000; i++) {
            int key = ran.nextInt(100000);
            rb.insert(key, 1);
            keys.add(key);
            if (rb.checkBalance() == false) {
                throw new Exception("error");
            } else {
                System.out.println("good:" + key);
            }
        }
        for (int key : keys) {
            rb.delete(key);
            if (rb.checkBalance() == false) {
                throw new Exception("error" + key);
            } else {
                //System.out.println("good");
            }
        }
    }
}
时间: 2024-11-05 16:26:51

红黑树的一个java实现的相关文章

红黑树的插入Java实现

package practice; public class TestMain { public static void main(String[] args) { int[] ao = {5, 1, 18, 3, 8, 20, 13, 16, 12}; Integer[] a = new Integer[9]; for (int i = 0; i < a.length; i++) { a[i] = new Integer(ao[i]); } RedBlackBST<Integer,Strin

java中treemap和treeset实现(红黑树)

TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点. TreeSet 和 TreeMap 的关系 为了让大家了解 TreeMap 和 TreeSet 之间的关系,下面先看 TreeSet 类的部分源代码: public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializab

Java集合详解6:这次,从头到尾带你解读Java中的红黑树

<Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下Star.fork哈 文章首发于我的个人博客: www.how2playlife.com 什么是红黑树 首先,什么是红黑树呢? 红黑树是一种"平衡的"二叉查找树,它是一种经典高效的算法,能够保证

红黑树(一)之 原理和算法详细介绍---转帖

目录1 红黑树的介绍2 红黑树的应用3 红黑树的时间复杂度和相关证明4 红黑树的基本操作(一) 左旋和右旋5 红黑树的基本操作(二) 添加6 红黑树的基本操作(三) 删除 作者:Sky Wang    于 2013-08-08 概述:R-B Tree,又称为"红黑树".本文参考了<算法导论>中红黑树相关知识,加之自己的理解,然后以图文的形式对红黑树进行说明.本文的主要内容包括:红黑树的特性,红黑树的时间复杂度和它的证明,红黑树的左旋.右旋.插入.删除等操作. 请尊重版权,转

算法导论之红黑树的学习

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

通过分析 JDK 源代码研究 TreeMap 红黑树算法实现

TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点. TreeSet 和 TreeMap 的关系 为了让大家了解 TreeMap 和 TreeSet 之间的关系,下面先看 TreeSet 类的部分源代码: public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializab

浅谈AVL树,红黑树,B树,B+树原理及应用

背景:这几天在看<高性能Mysql>,在看到创建高性能的索引,书上说mysql的存储引擎InnoDB采用的索引类型是B+Tree,那么,大家有没有产生这样一个疑问,对于数据索引,为什么要使用B+Tree这种数据结构,和其它树相比,它能体现的优点在哪里? 看完这篇文章你就会了解到这些数据结构的原理以及它们各自的应用场景. 二叉查找树 简介 二叉查找树也称为有序二叉查找树,满足二叉查找树的一般性质,是指一棵空树具有如下性质: 任意节点左子树不为空,则左子树的值均小于根节点的值. 任意节点右子树不为

【转】红黑树(一)原理与算法详细介绍

讲的通俗易懂,忍不住内心的欢喜,独乐乐不如众乐乐,下面贴出博文及地址: 概要 目录1 红黑树的介绍2 红黑树的应用3 红黑树的时间复杂度和相关证明4 红黑树的基本操作(一) 左旋和右旋5 红黑树的基本操作(二) 添加6 红黑树的基本操作(三) 删除 [转]  作者:Sky Wang :http://www.cnblogs.com/skywang12345/p/3245399.html 更多内容: 数据结构与算法系列 目录 (01) 红黑树(一)之 原理和算法详细介绍(02) 红黑树(二)之 C语

红黑树和AVL树的比较

1. 红黑树并不追求"完全平衡"--它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能. 红黑树能够以O(log2 n) 的时间复杂度进行搜索.插入.删除操作.此外,由于它的设计,任何不平衡都会在三次旋转之内解决.当然,还有一些更好的,但实现起来更复杂的数据结构,能够做到一步旋转之内达到平衡,但红黑树能够给我们一个比较"便宜"的解决方案.红黑树的算法时间复杂度和AVL相同,但统计性能比AVL树更高. 当然,红黑树并不适应所有应用树的领域.如果数据基本上是