• TreeMap 红黑树实现


    TreeMap 是一个有序的key-value集合,它是通过 红黑树 实现的。

    TreeMap 继承于AbstractMap,所以它是一个Map,即一个key-value集合。

    TreeMap 实现了NavigableMap,Cloneable和Serializable接口。

    TreeMap的基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n) 。

    首先是TreeMap的构造方法:

      public TreeMap() {
            comparator = null;
        }
    /** * Constructs a new, empty tree map, ordered according to the given comparator. */ public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator; } /** * Constructs a new tree map containing the same mappings as the given * map, ordered according to the <em>natural ordering</em> of its keys. */ public TreeMap(Map<? extends K, ? extends V> m) { comparator = null; putAll(m); } /** * Constructs a new tree map containing the same mappings and * using the same ordering as the specified sorted map. This * method runs in linear time. */ public TreeMap(SortedMap<K, ? extends V> m) { comparator = m.comparator(); try { buildFromSorted(m.size(), m.entrySet().iterator(), null, null); } catch (java.io.IOException cannotHappen) { } catch (ClassNotFoundException cannotHappen) { } }

    TreeMap是基于红黑树实现的,以下是树结点的定义,主要key(键)、value(值)、left(左孩子)、right(右孩子)、parent(父节点)、color(颜色)六个字段,根据key的值进行排序。该内部类比较简单,不做分析。

        static final class Entry<K,V> implements Map.Entry<K,V> {
            K key;
            V value;
            Entry<K,V> left = null;
            Entry<K,V> right = null;
            Entry<K,V> parent;
            boolean color = BLACK;
    
            /**
             * Make a new cell with given key, value, and parent, and with
             * {@code null} child links, and BLACK color.
             */
            Entry(K key, V value, Entry<K,V> parent) {
                this.key = key;
                this.value = value;
                this.parent = parent;
            }
    
            ......
      }

    以下是红黑树的插入put和删除deleteEntry操作,以及执行插入删除时需要用到的操作:左旋rotateLeft、右旋rotateRight、插入修正fixAfterInsertion和删除修正fixAfterDeletion。

    插入操作,先找到要插入的位置,插入新结点,调用fixAfterInsertion对插入结果进行修正:

        public V put(K key, V value) {
            Entry<K,V> t = root;
            if (t == null) {
                compare(key, key); // type (and possibly null) check
    
                root = new Entry<>(key, value, null);
                size = 1;
                modCount++;
                return null;
            }
            int cmp;
            Entry<K,V> parent;
            // split comparator and comparable paths
            Comparator<? super K> cpr = comparator;
            if (cpr != null) {
                do {
                    parent = t;
                    cmp = cpr.compare(key, t.key);
                    if (cmp < 0)
                        t = t.left;
                    else if (cmp > 0)
                        t = t.right;
                    else
                        return t.setValue(value);
                } while (t != null);
            }
            else {
                if (key == null)
                    throw new NullPointerException();
                Comparable<? super K> k = (Comparable<? super K>) key;
                do {
                    parent = t;
                    cmp = k.compareTo(t.key);
                    if (cmp < 0)
                        t = t.left;
                    else if (cmp > 0)
                        t = t.right;
                    else
                        return t.setValue(value);
                } while (t != null);
            }
            Entry<K,V> e = new Entry<>(key, value, parent);
            if (cmp < 0)
                parent.left = e;
            else
                parent.right = e;
            fixAfterInsertion(e);
            size++;
            modCount++;
            return null;
        }

     fixAfterInsertion操作,保证插入节点之后,仍然是一棵红黑树:

         private void fixAfterInsertion(Entry<K, V> x) {
            x.color = RED;
            while (x != null && x != root && x.parent.color == RED) {            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
                    Entry<K, V> y = rightOf(parentOf(parentOf(x))); 
                    if (colorOf(y) == RED) {
                        setColor(parentOf(x), BLACK);
                        setColor(y, BLACK);
                        setColor(parentOf(parentOf(x)), RED);
                        x = parentOf(parentOf(x);
                    } else {
                        if (x == rightOf(parentOf(x))) {
                            x = parentOf(x)
                            rotateLeft(x);
                        }
                        setColor(parentOf(x), BLACK);
                        setColor(parentOf(parentOf(x)), RED);
                        rotateRight(parentOf(parentOf(x)));
                    }            } else {
                    Entry<K, V> y = leftOf(parentOf(parentOf(x))); 
                    if (colorOf(y) == RED) {
                        setColor(parentOf(x), BLACK);
                        setColor(y, BLACK);
                        setColor(parentOf(parentOf(x)), RED);
                        x = parentOf(parentOf(x);
                    } else {
                        if (x == leftOf(parentOf(x))) {
                            x = parentOf(x)
                            rotateRight(x);
                        }
                        setColor(parentOf(x), BLACK);
                        setColor(parentOf(parentOf(x)), RED);
                        rotateLeft(parentOf(parentOf(x)));
                    }
                }
            }
            root.COLOR = BLACK;
        }

    之中用到了leftRotate和rightRotate操作,这里先介绍这两个操作,在fixAfterDeletion中也会用到:

        private void rotateLeft(Entry<K,V> p) {
            if (p != null) {
                Entry<K,V> r = p.right;
                p.right = r.left;
                if (r.left != null)
                    r.left.parent = p;
                r.parent = p.parent;
                if (p.parent == null)
                    root = r;
                else if (p.parent.left == p)
                    p.parent.left = r;
                else
                    p.parent.right = r;
                r.left = p;
                p.parent = r;
            }
        }
    
        private void rotateRight(Entry<K,V> p) {
            if (p != null) {
                Entry<K,V> l = p.left;
                p.left = l.right;
                if (l.right != null)
                    l.right.parent = p;
                l.parent = p.parent;
                if (p.parent == null)
                    root = l;
                else if (p.parent.right == p)
                    p.parent.right = l;
                else p.parent.left = l;
                l.right = p;
                p.parent = l;
            }
        }

    删除操作,先按二叉查找树的方法删除节点,然后调用fixAfterDeletion使得树保持红黑树性质:

        private void deleteEntry(Entry<K, V> p) {
            modCount++;
            size--;
            if (p.left != null && p.right != null) {
                Entry<K, V> s = successor(p);
                p.key = s.key;
                p.value = s.value;
                p = s;
            }
    
            Entry<K,V> replacement = p.left != null ? p.left : p.right;
            if (replacement != null) {
                replacement.parent = p.parent;
                if (p.parent == null)
                    root = replacement;
                else if (p == p.parent.left)
                    p.parent.left = replacement;
                else
                    p.parent.right = replacement;
                p.left = p.right = p.parent = null;
                if (p.COLOR == BLACK)
                    fixAfterDeletion(replacement);
            } else if (p.parent == NULL) {
                root = null;
            } else {
                if (p.color == BLACK)
                    fixAfterDeletion(p);
                if (p.parent != null) {
                    if (p ==p.parent.left)
                        p.parent.left = null;
                    else
                        p.parent.right = null;
                    p.parent = null;
                }
            }
        }
  • 相关阅读:
    Nginx负载均衡和LVS负载均衡的比较分析
    Nginx和Squid配合搭建的Web服务器前端系统
    (总结)Linux服务器上最简单的Nginx反向代理配置
    Nginx主要模块常用指令说明
    (总结)Nginx 502 Bad Gateway错误触发条件与解决方法
    (总结)Linux下查看Nginx Apache MySQL的并发连接数和连接状态
    (总结)统计Apache或Nginx访问日志里的独立IP访问数量的Shell
    IoC模式(依赖、依赖倒置、依赖注入、控制反转)
    使用OAuth打造webapi认证服务供自己的客户端使用
    RESTful API 设计指南
  • 原文地址:https://www.cnblogs.com/yitong0768/p/4561608.html
Copyright © 2020-2023  润新知