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日

相关文章

  • 稀疏数组

    引入 当在网页上下棋类游戏时,玩到中途想要离开,但是我们需要保存进度,方便下次继续 我们应该怎么实现 ? 以围棋举例 使用二维数组将棋盘记下 ,如 0 为 没有棋子 ,1 为 黑子 , 2为白子 但是没有棋子的地方都为 0 ,整个二维数组充斥着大量的无效数据 0 我们需要想一个办法来 优化存储的方式 基本介绍 当一个数组中大部分元素是同一个值时,我们可以使用…

    算法与数据结构 2023年4月19日
    00
  • C语言数据结构与算法之排序总结(二)

    C语言数据结构与算法之排序总结(二) 本篇文章是关于C语言数据结构与算法中排序算法的详细讲解,涉及了八种排序算法。 冒泡排序(Bubble Sort) 冒泡排序是一种简单的排序算法。在排序过程中,它会重复地交换相邻的元素,这是它名称的由来。 示例代码: c void bubble_sort(int arr[], int n) { for (int i = 0…

    数据结构 2023年5月17日
    00
  • 考研数据结构模板:顺序表、链表、栈、队列

    考研数据结构模板:顺序表、链表、栈、队列 前言 代码风格偏向于考研风格而非算法竞赛风格。 代码实现参考《2024数据结构王道复习指导》。 注释详细、保证看懂。 下面是已实现的数据结构模板: 顺序表SeqList 链表LinkList 双链表DLinkList 顺序栈SeqStack 循环顺序队列CircleQueue 链队列LinkQueue 顺序表SeqL…

    算法与数据结构 2023年4月17日
    00
  • 查询json的数据结构的8种方式简介

    查询json的数据结构的8种方式简介 在处理JSON数据时,经常需要提取特定的数据或获取某个属性的值。这时候就需要使用JSON的查询语言来进行查询操作。本文将介绍8种常用的JSON查询方式,帮助大家更方便、快捷地查询和分析JSON数据。 1. 点语法 使用点语法(.)查询JSON数据是最简单、最常用的方式,通过指定属性名来获取相应的值。例如,假设有以下的JS…

    数据结构 2023年5月17日
    00
  • 详解C语言实现空间索引四叉树

    详解C语言实现空间索引四叉树攻略 四叉树是一种常见的空间索引方法,可以有效地处理二维或三维空间中的数据。本攻略将详细介绍使用C语言实现空间索引四叉树的方法,包括数据结构的设计,插入和查询操作的实现。 数据结构设计 结点结构体 struct QuadtreeNode { int depth; // 结点深度 double x, y; // 结点中心坐标 dou…

    数据结构 2023年5月17日
    00
  • Java数据结构学习之二叉树

    Java数据结构学习之二叉树 什么是二叉树 二叉树是一种树形数据结构,他的每个节点最多有两个子节点,分别称为左子节点和右子节点。如果一个节点没有子节点,则成为叶子节点。二叉树具有以下性质: 每个节点最多有两个子节点 左子树和右子树是二叉树 二叉树可以为空 二叉树的遍历 为了遍历一棵树,我们可以采用两种算法: 深度优先遍历 深度优先遍历的思路是:从根节点出发,…

    数据结构 2023年5月17日
    00
  • C语言单链队列的表示与实现实例详解

    C语言单链队列的表示与实现实例详解 什么是队列? 在计算机科学中,队列(Queue)是一种特殊的数据结构,它只允许在一端进行插入操作,在另一端进行删除操作。将新元素插入队列的过程可以称之为入队,而将元素从队列中删除的过程则可以称之为出队。队列的核心思想是“先进先出”(First In First Out,FIFO),即先入队的元素先出队。 单链队列的表示方式…

    数据结构 2023年5月17日
    00
  • C++数据结构与算法之反转链表的方法详解

    C++数据结构与算法之反转链表的方法详解 在C++中,反转链表是一种常见的数据结构与算法技巧。在本文中,我们将详细讲解反转链表的实现过程以及常见的两种反转方法。 基本定义 在开始讲述反转链表算法之前,我们先介绍一下链表的基本定义。 链表是一种数据结构,其中每个节点包含一个数据元素和一个指向下一个节点的指针。下面是一个简单的链表的节点结构定义: struct …

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部