Java实现红黑树

Posted StubbornAnt

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java实现红黑树相关的知识,希望对你有一定的参考价值。

红黑树概要

  • 二叉查找树实现了基本操作时间复杂度O(h),但是树的高度h在最坏的情况下可能变为n
  • 红黑树是一种平衡二叉树,可以保证树的高度 h = lg(N)

红黑树的性质

红黑树为每个节点添加了颜色存储位,确保了任何一个从根到叶子的路径长度不会比其他路径长出2倍

  1. 每个节点是红色或者黑色
  2. 根节点是黑色的
  3. 叶子节点是黑色的
  4. 红色节点的子节点都是黑色的
  5. 当前节点到其后代叶子节点的所有简单路径路的黑色节点数目相同

性质4确保了根节点到任意叶子节点的路径长度不会比到其他叶子节点的路径长度长出2倍。例如,黑高为3的树最短路径为2(黑-黑-黑(外部节点)),最长路径为4(黑-红-黑-红-黑(外部节点)),从而一棵n个节点的红黑树高度最大为2lg(n+1)

红黑树实现代码

经过旋转后,二叉搜索树的性质保持

public class RedBlackTree 
    private TreeNode root = TreeNode.nil;
    public TreeNode minimum() 
        TreeNode node = minimum(root);
        if (node == TreeNode.nil) 
            return null;
        
        return node;
    
    public TreeNode maximum() 
        TreeNode node = maximum(root);
        if (node == TreeNode.nil) 
            return null;
        
        return node;
    
    public TreeNode successor(TreeNode x) 
        if (x == TreeNode.nil) 
            return null;
        
        if (x.right != TreeNode.nil) 
            return minimum(x.right);
         else 
            TreeNode y = x.p;
            while (y != null && x == y.right) 
                x = y;
                y = y.p;
            
            return y;
        
    
    public TreeNode predecessor(TreeNode x) 
        if (x == TreeNode.nil) 
            return null;
        
        if (x.left != TreeNode.nil) 
            return maximum(x.left);
         else 
            TreeNode y = x.p;
            while (y != null && x == y.left) 
                x = y;
                y = y.p;
            
            return y;
        
    
    public TreeNode search(int key) 
        TreeNode node = root;
        while (node != TreeNode.nil) 
            if (key < node.key) 
                node = node.left;
             else if (key > node.key) 
                node = node.right;
             else 
                return node;
            
        
        return null;
    
    public void insert(TreeNode node) 
        TreeNode p = TreeNode.nil;
        TreeNode t = root;
        while (t != TreeNode.nil) 
            p = t;
            if (node.key < t.key) 
                t = t.left;
             else 
                t = t.right;
            
        
        node.p = p;
        if (p == TreeNode.nil) 
            root = node;
         else if (node.key > p.key) 
            p.right = node;
         else 
            p.left = node;
        
        node.color = Color.RED;
        node.left = TreeNode.nil;
        node.right = TreeNode.nil;
        insertionFixup(node);
    
    public void delete(TreeNode z) 
        TreeNode y = z;
        TreeNode x = TreeNode.nil;
        Color originalColor = y.color;
        if (z.left == TreeNode.nil) 
            x = z.right;
            transplant(z, z.right);
         else if (z.right == TreeNode.nil) 
            x = z.left;
            transplant(z, z.left);
         else 
            y = minimum(z.right);
            originalColor = y.color;
            x = y.right;
            if (y.p == z) 
                x.p = y;
             else 
                transplant(y, y.right);
                y.right = z.right;
                y.right.p = y;
            
            transplant(z, y);
            y.left = z.left;
            y.left.p = y;
            y.color = z.color;
        
        if (originalColor == Color.BLACK) 
            deletionFixup(x);
        
    
    private void deletionFixup(TreeNode x) 
        while (x != root && x.color == Color.BLACK) 
            if (x == x.p.left) 
                TreeNode w = x.p.right;
                if (w.color == Color.RED) 
                    w.color = Color.BLACK;
                    w.p.color = Color.RED;
                    leftRotate(x.p);
                    w = x.p.right;
                 else if (w.left.color == Color.BLACK && w.right.color == Color.BLACK) 
                    w.color = Color.RED;
                    x = x.p;
                 else if (w.right.color == Color.BLACK) 
                    w.left.color = Color.BLACK;
                    w.color = Color.RED;
                    rightRotate(w);
                    w = x.p.right;
                 else 
                    w.color = x.p.color;
                    x.p.color = Color.BLACK;
                    w.right.color = Color.BLACK;
                    leftRotate(x.p);
                    x = root;
                
             else 
                TreeNode w = x.p.left;
                if (w.color == Color.RED) 
                    w.color = Color.BLACK;
                    w.p.color = Color.RED;
                    rightRotate(x.p);
                    w = x.p.left;
                 else if (w.right.color == Color.BLACK && w.left.color == Color.BLACK) 
                    w.color = Color.RED;
                    x = x.p;
                 else if (w.left.color == Color.BLACK) 
                    w.right.color = Color.BLACK;
                    w.color = Color.RED;
                    leftRotate(w);
                    w = x.p.left;
                 else 
                    w.color = x.p.color;
                    x.p.color = Color.BLACK;
                    w.left.color = Color.BLACK;
                    rightRotate(x.p);
                    x = root;
                
            
        
        x.color = Color.BLACK;
    
    private TreeNode minimum(TreeNode x) 
        if (root == TreeNode.nil) 
            return TreeNode.nil;
        
        while (x.left != TreeNode.nil) 
            x = x.left;
        
        return x;
    
    private TreeNode maximum(TreeNode x) 
        if (x == TreeNode.nil) 
            return TreeNode.nil;
        
        while (x.right != TreeNode.nil) 
            x = x.right;
        
        return x;
    
    private void transplant(TreeNode u, TreeNode v) 
        if (u.p == TreeNode.nil) 
            root = v;
         else if (u == u.p.left) 
            u.p.left = v;
         else 
            u.p.right = v;
        
        v.p = u.p;
    

    private void leftRotate(TreeNode x) 
        TreeNode y = x.right;
        x.right = y.left;
        if (y.left != TreeNode.nil) 
            y.left.p = x;
        
        if (x.p == TreeNode.nil) 
            root = y;
         else if (x == x.p.left) 
            x.p.left = y;
         else 
            x.p.right = y;
        
        y.p = x.p;
        y.left = x;
        x.p = y;
    

    private void rightRotate(TreeNode x) 
        TreeNode y = x.left;
        x.left = y.right;
        if (y.right != TreeNode.nil) 
            y.right.p = x;
        
        if (x.p == TreeNode.nil) 
            root = y;
         else if (x == x.p.left) 
            x.p.left = y;
         else 
            x.p.right = y;
        
        y.p = x.p;
        y.right = x;
        x.p = y;
    

    private void insertionFixup(TreeNode z) 
        while (z.p.color == Color.RED) 
            if (z.p == z.p.p.left) 
                TreeNode y = z.p.p.right;
                if (y.color == Color.RED) 
                    z.p.color = Color.BLACK;
                    y.color = Color.BLACK;
                    z.p.p.color = Color.RED;
                    z = z.p.p;
                 else if (z == z.p.right) 
                    z = z.p;
                    leftRotate(z);
                 else 
                    z.p.color = Color.BLACK;
                    z.p.p.color = Color.RED;
                    rightRotate(z.p.p);
                
             else 
                TreeNode y = z.p.p.left;
                if (y.color == Color.RED) 
                    z.p.color = Color.BLACK;
                    y.color = Color.BLACK;
                    z.p.p.color = Color.RED;
                    z = z.p.p;
                 else if (z == z.p.left) 
                    z = z.p;
                    rightRotate(z);
                 else 
                    z.p.color = Color.BLACK;
                    z.p.p.color = Color.RED;
                    leftRotate(z.p.p);
                
            
        
        root.color = Color.BLACK;
    

    @Override
    public String toString() 
        Queue<TreeNode> q = new LinkedList<TreeNode>();
        StringBuilder sb = new StringBuilder();
        q.offer(root);
        while (!q.isEmpty()) 
            TreeNode node = q.poll();
            if (node == TreeNode.nil) 
                sb.append("#");
                continue;
             else 
                sb.append(node);
                q.offer(node.left);
                q.offer(node.right);
            
        
        int p = sb.length();
        while (p > 0) 
            if (sb.charAt(p - 1) != '#') 
                break;
            
            p--;
        
        return sb.substring(0, p).toString();
    

    static class TreeNode 
        public static final TreeNode nil = new TreeNode(0);
        Color color = Color.BLACK;
        int key;
        TreeNode left = nil;
        TreeNode right = nil;
        TreeNode p = nil;
        public TreeNode(int key) 
            this.key = key;
        
        @Override
        public String toString() 
            return "(" + key + " " + color + ")";
        
    
    enum Color 
        RED, BLACK;
    
    public static void main(String[] args) 
        TreeNode root = new TreeNode(0);
        TreeNode one = new TreeNode(1);
        TreeNode two = new TreeNode(2);
        TreeNode three = new TreeNode(3);
        TreeNode four = new TreeNode(4);
        TreeNode five = new TreeNode(5);
        RedBlackTree rbt = new RedBlackTree();
        rbt.insert(one);
        rbt.insert(three);
        rbt.insert(root);
        rbt.insert(four);
        rbt.insert(five);
        rbt.insert(two);
        printTree(rbt);
        rbt.delete(five);
        printTree(rbt);
    
  

以上是关于Java实现红黑树的主要内容,如果未能解决你的问题,请参考以下文章

数据结构关联式容器底层红黑树的模拟实现

数据结构关联式容器底层红黑树的模拟实现

红黑树(python)-1插入

Java实现红黑树

红黑树操作

红黑树