Java实现红黑树

简介: 红黑树概要二叉查找树实现了基本操作时间复杂度O(h),但是树的高度h在最坏的情况下可能变为n红黑树是一种平衡二叉树,可以保证树的高度 h = lg(N)红黑树的性质红黑树为每个节点添加了颜色存储位,确保了任何一个从根到叶子的路径长度不会比其他路径长出2倍每个节点是红色或者黑色根节点是黑色的叶子节点是黑色的红色节点的子节点都是黑色的当前节点到其后代叶子节点的所有简单路径路的黑色节点数目相同性质4确保了根节点到任意叶子节点的路径长度不会比到其他叶子节点的路径长度长出2倍。

红黑树概要

  • 二叉查找树实现了基本操作时间复杂度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);
    }
}  
目录
相关文章
|
2月前
|
存储 算法 安全
【Java编程进阶之路 02】深入探索:红黑树如何重塑哈希表的性能边界
JDK 1.8之后,HashMap引入红黑树来优化性能,当链表长度超过阈值(默认为8)时,链表会转换为红黑树,从而提高高冲突时的查询效率。同时,HashMap也采用了扰动函数来增加哈希值的随机性,使键值对更均匀分布,提升性能。
|
2月前
|
存储 Java
Java TreeMap:基于红黑树的排序映射解析
Java TreeMap:基于红黑树的排序映射解析
|
2月前
|
安全 Java
Java TreeSet:基于红黑树的排序集合解析
Java TreeSet:基于红黑树的排序集合解析
|
8月前
|
存储 算法 Java
深入解析 Java 数据结构:红黑树的特点与应用
红黑树(Red-Black Tree)是一种自平衡的二叉搜索树,它在 Java 编程中扮演着重要的角色,用于高效地存储和管理数据。红黑树的特点使其在查找、插入和删除操作中保持相对平衡,从而提供了稳定且高效的性能。本文将深入探讨红黑树的特点、用法、实现方式以及在实际应用中的优势。
|
6月前
|
存储 缓存 算法
【JavaSE专栏54】Java集合类TreeMap解析,基于红黑树的键值对存储结构
【JavaSE专栏54】Java集合类TreeMap解析,基于红黑树的键值对存储结构
|
6月前
|
存储 安全 Java
【JavaSE专栏52】Java集合类TreeSet解析,基于红黑树实现的有序非重集合
【JavaSE专栏52】Java集合类TreeSet解析,基于红黑树实现的有序非重集合
|
7月前
|
Java
Java二叉树和红黑树
Java二叉树和红黑树
43 0
|
8月前
|
存储 算法 Java
红黑树【数据结构与算法Java】
红黑树【数据结构与算法Java】
38 0
|
9月前
|
Java
|
10月前
|
算法 Java 容器
JAVA中的红黑树
在开始讨论JAVA中的红黑树之前,就前几篇关于二叉树的文章做个总结。 平衡二叉树:高度差绝对值不超过1,任意节点左右子树均为平衡二叉树。 AVL树:平衡二叉树只是一个概念,AVL树,红黑树都是这个概念的落地实现。AVL树其实就是《手撕JAVA十三》一文中说的通过RR,RL,LL,LR旋转而成的平衡二叉树。这些旋转都属于AVL树的算法。
72 0