Java红黑树的数据结构与算法解析

Java红黑树的数据结构与算法解析

红黑树简介

红黑树是一种平衡二叉搜索树,其中的每个节点上都有一个黑色或红色的标记,并且满足以下性质:

  1. 根节点是黑色的;
  2. 叶子节点是黑色的空节点(NULL);
  3. 如果一个节点是红色的,则其子节点必须是黑色的;
  4. 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点;
  5. 新插入的节点默认是红色的。

具体来说,只有在删除或者某些特殊的插入操作之后,才会涉及到红黑树的平衡调整。

红黑树可以用于实现有序的映射表数据结构。Java 中的 TreeMap 就是基于红黑树实现的。

红黑树的基本操作

红黑树支持的操作包括:

  • add(e): 插入元素 e;
  • remove(e): 删除元素 e;
  • find(e): 查找元素 e;
  • floor(e): 返回小于等于 e 的最大元素;
  • ceiling(e): 返回大于等于 e 的最小元素;
  • lower(e): 返回小于 e 的最大元素;
  • higher(e): 返回大于 e 的最小元素;
  • first(): 返回树中最小元素;
  • last(): 返回树中最大元素。

这些操作都可以在 $O(\log(n))$ 的时间内完成。

红黑树实现示例

以下是基于 Java 实现的红黑树示例代码:

public class RedBlackTree<K extends Comparable<K>, V> {
    private static final boolean RED = true;
    private static final boolean BLACK = false;

    private class Node {
        public K key;
        public V value;
        public Node left, right;
        public boolean color;

        public Node(K key, V value) {
            this.key = key;
            this.value = value;
            left = null;
            right = null;
            color = RED;
        }
    }

    private Node root;
    private int size;

    public RedBlackTree() {
        root = null;
        size = 0;
    }

    public int getSize() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    private boolean isRed(Node node) {
        if (node == null)
            return BLACK;
        return node.color;
    }

    private Node leftRotate(Node node) {
        Node x = node.right;
        node.right = x.left;
        x.left = node;

        x.color = node.color;
        node.color = RED;

        return x;
    }

    private Node rightRotate(Node node) {
        Node x = node.left;
        node.left = x.right;
        x.right = node;

        x.color = node.color;
        node.color = RED;

        return x;
    }

    private void flipColors(Node node) {
        node.color = RED;
        node.left.color = BLACK;
        node.right.color = BLACK;
    }

    public void add(K key, V value) {
        root = add(root, key, value);
        root.color = BLACK;
    }

    private Node add(Node node, K key, V value) {
        if (node == null) {
            size++;
            return new Node(key, value);
        }

        if (key.compareTo(node.key) < 0)
            node.left = add(node.left, key, value);
        else if (key.compareTo(node.key) > 0)
            node.right = add(node.right, key, value);
        else
            node.value = value;

        if (isRed(node.right) && !isRed(node.left))
            node = leftRotate(node);

        if (isRed(node.left) && isRed(node.left.left))
            node = rightRotate(node);

        if (isRed(node.left) && isRed(node.right))
            flipColors(node);

        return node;
    }

    private Node getNode(Node node, K key) {
        if (node == null)
            return null;

        if (key.equals(node.key))
            return node;
        else if (key.compareTo(node.key) < 0)
            return getNode(node.left, key);
        else
            return getNode(node.right, key);
    }

    public boolean contains(K key) {
        return getNode(root, key) != null;
    }

    public V get(K key) {
        Node node = getNode(root, key);
        return node == null ? null : node.value;
    }

    public void set(K key, V newValue) {
        Node node = getNode(root, key);
        if (node == null)
            throw new IllegalArgumentException(key + " doesn't exist in the BST.");

        node.value = newValue;
    }

    public Node minimum(Node node) {
        if (node.left == null)
            return node;
        return minimum(node.left);
    }

    public V remove(K key) {
        Node node = getNode(root, key);
        if (node != null) {
            root = remove(root, key);
            return node.value;
        }
        return null;
    }

    private Node remove(Node node, K key) {
        if (node == null)
            return null;

        if (key.compareTo(node.key) < 0) {
            node.left = remove(node.left, key);
            return node;
        } else if (key.compareTo(node.key) > 0) {
            node.right = remove(node.right, key);
            return node;
        } else {
            //key.compareTo(node.key) == 0
            if (node.left == null) {
                Node rightNode = node.right;
                node.right = null;
                size--;
                return rightNode;
            }

            if (node.right == null) {
                Node leftNode = node.left;
                node.left = null;
                size--;
                return leftNode;
            }

            Node successor = minimum(node.right);
            successor.right = remove(node.right, successor.key);
            successor.left = node.left;

            node.left = node.right = null;

            return successor;
        }
    }
}

红黑树应用示例

以下是一个使用红黑树实现有序集合的示例代码:

public class TreeSet<E extends Comparable<E>> implements Set<E> {
    private RedBlackTree<E, Object> tree;

    public TreeSet() {
        tree = new RedBlackTree<>();
    }

    public int size() {
        return tree.getSize();
    }

    public boolean isEmpty() {
        return tree.isEmpty();
    }

    public boolean contains(Object o) {
        return tree.contains((E)o);
    }

    public boolean add(E e) {
        Object obj = tree.add(e, null);
        return obj == null;
    }

    public boolean remove(Object o) {
        Object obj = tree.remove((E)o);
        return obj != null;
    }

    public void clear() {
        tree = new RedBlackTree<>();
    }

    public Iterator<E> iterator() {
        return new TreeSetIterator(tree);
    }

    private class TreeSetIterator implements Iterator<E> {
        private Iterator<RedBlackTree.Node> iterator;

        public TreeSetIterator(RedBlackTree<E, Object> tree) {
            iterator = new RedBlackTreeIterator(tree);
        }

        public boolean hasNext() {
            return iterator.hasNext();
        }

        public E next() {
            RedBlackTree.Node node = iterator.next();
            return (E)node.key;
        }

        public void remove() {
            iterator.remove();
        }
    }

    private class RedBlackTreeIterator implements Iterator<RedBlackTree.Node> {
        private Stack<RedBlackTree.Node> stack;

        public RedBlackTreeIterator(RedBlackTree<E, Object> tree) {
            stack = new Stack<>();

            RedBlackTree.Node cur = tree.getRoot();
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
        }

        public boolean hasNext() {
            return !stack.isEmpty();
        }

        public RedBlackTree.Node next() {
            RedBlackTree.Node cur = stack.pop();

            if (cur.right != null) {
                RedBlackTree.Node right = cur.right;
                while (right != null) {
                    stack.push(right);
                    right = right.left;
                }
            }

            return cur;
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}

该示例代码实现了一个基于红黑树实现的有序集合。其中,set 的基本操作都可以在 $O(\log(n))$ 的时间内完成。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java红黑树的数据结构与算法解析 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • C语言实现带头结点的链表的创建、查找、插入、删除操作

    C语言实现带头结点的链表的创建、查找、插入、删除操作攻略 一、链表基本概念 链表是一种动态的数据结构,它可以在运行时动态地分配内存,支持数据的插入、删除等操作。链表(Linked List)由多个节点(Node)组成,每个节点包含两部分,一个是数据部分(Data),另一个是指向下一个节点的指针(Next)。 二、带头结点的链表 带头结点的链表是一种特殊的链表…

    数据结构 2023年5月17日
    00
  • Java 数据结构与算法系列精讲之哈希算法实现

    Java 数据结构与算法系列精讲之哈希算法实现 什么是哈希算法? 哈希算法是一种能将任意长度的消息压缩到某一固定长度的消息摘要的算法。 通过哈希算法,我们可以将一个任意的大数据量压缩成一段固定长度的数据,这个数据的长度通常比较小,相对于原数据的大小来说,要小得多。哈希算法的压缩特性使得它经常用来进行信息摘要、数据校验、唯一识别等功能,可以很大程度上提高数据的…

    数据结构 2023年5月17日
    00
  • 8个简单部分开启Java语言学习之路 附java学习书单

    8个简单部分开启Java语言学习之路 如果你想要学习Java语言,但是不知道从何入手,在这里,我们将为你提供一份简单易懂的攻略,分8个步骤带你开启Java语言学习之路。 1. 安装Java开发工具 Java学习的第一步是安装Java开发工具,目前比较流行的Java开发工具有多种,例如Eclipse、Intellij IDEA、NetBeans等。本攻略以In…

    数据结构 2023年5月17日
    00
  • Java数据结构之对象的比较

    Java数据结构之对象的比较 在Java中,对象的比较是非常重要的操作。我们常常需要对不同的对象进行比较,以便对它们进行排序、按照某个条件过滤等操作。本文将详细讲解Java中对象的比较,并给出一些示例来说明。 对象的比较方法 Java中有两种对象比较方法:值比较和引用比较。值比较就是比较两个对象的值是否相等,而引用比较是比较两个对象是否是同一个对象。 值比较…

    数据结构 2023年5月17日
    00
  • java数据结构之实现双向链表的示例

    Java数据结构之实现双向链表的示例 1. 什么是双向链表? 双向链表,英文名为doubly linked list,是一种链表结构。与单向链表不同,双向链表中的每一个节点除了保存了指向下一个节点的指针外,还保存了指向前一个节点的指针。因此,双向链表可双向遍历,可以从前向后或从后向前遍历。 2. 双向链表的实现 2.1 节点类的实现 创建节点类Node,并定…

    数据结构 2023年5月17日
    00
  • C++数据结构的队列详解

    C++数据结构的队列详解 队列是什么? 队列是一种先进先出(First In First Out, FIFO)的数据结构,类似于现实生活中的排队等待服务。 队列中的数据按照先进先出的原则被处理。新的元素只能被插入在队列的末尾,而旧的元素只能从队列的开头被删除。因此,队列的末尾称为队尾,队列的开头被称为队头。 队列的实现方式 数组实现方式 队列可以使用数组实现…

    数据结构 2023年5月17日
    00
  • C语言数据结构之栈简单操作

    C语言数据结构之栈简单操作 什么是栈? 栈(Stack)是一种线性数据结构,它具有“后进先出”(Last-In-First-Out)的特性。栈顶是栈的一端,另一端称为栈底。每次只能从栈顶插入数据(入栈)或者从栈顶取出数据(出栈)。 栈的简单操作 栈的简单操作包括: 初始化栈 判断栈是否为空 判断栈是否已满 入栈操作 出栈操作 获取栈顶元素 栈的初始化 栈的初…

    数据结构 2023年5月16日
    00
  • 「枚举」组合的输出

    本题为3月23日23上半学期集训每日一题中B题的题解 题面 (写题解的时候学校oj已不可查看此题,下面的题面来自洛谷第1157题) 题目描述 排列与组合是常用的数学方法,其中组合就是从 \(n\) 个元素中抽出 \(r\) 个元素(不分顺序且 \(r \le n\)),我们可以简单地将 \(n\) 个元素理解为自然数 \(1,2,\dots,n\),从中任取…

    算法与数据结构 2023年4月18日
    00
合作推广
合作推广
分享本页
返回顶部