TreeMap

SortedMap接口表示它的 Key是有序、不可重复的

TreeMap 依靠 Comparable 或Comparator 来实现 Key 的去重

HashMap 是 使用 hashCode 和 equals 实现去重

    /**
     * Compares two keys using the correct comparison method for this TreeMap.
     */
    @SuppressWarnings("unchecked")
    final int compare(Object k1, Object k2) {
        return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
            : comparator.compare((K)k1, (K)k2);
    }

如果 comparator为空 调用对象的compareTo进行比较 否则 使用comparator.compare 进行比较

两者都无法满足 , 则抛出异常

 

属性:

	// 排序使用的比较器
    private final Comparator<? super K> comparator;
		// 根节点
    private transient Entry<K,V> root;
    
    //将红 黑色 定义成有含义的常量
    private static final boolean RED   = false;
    private static final boolean BLACK = true;
		//树  节点个数
    private transient int size = 0;
		//变化次数
    private transient int modCount = 0;
    
    //静态内部类  存储节点 中的 key value 数据结构
    static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;
        V value;
        Entry<K,V> left;  // 左子引用
        Entry<K,V> right;  // 右子引用
        Entry<K,V> parent;  // 父节点引用
        boolean color = BLACK;  //  节点默认颜色为黑色

put()和 deleteEntry()实现红黑树的增加和删除节点操作

以插入主流程为例:

三个前提:

 1 需要调整的新节点只为红色的

 2 插入的新节点的父节点是黑色的无需调整

 3 如父节点为红色的,则需要调整:循环判断、重新着色、左右旋转

	public V put(K key, V value) {
  			// t表示当前节点  被赋值为根节点的引用
        Entry<K,V> t = root;
        // 如果根节点为null  则当前节点设置为根节点
        if (t == null) {
            //校验 key是否可比较
            compare(key, key); // type (and possibly null) check
						// 创建当前节点 并赋值给root  parent为null
            root = new Entry<>(key, value, null);
            // 更新节点数目
            size = 1;
            // 变更次数增加
            modCount++;
            return null;
        }
        // 接收比较结果  用于确定待插入节点应该放在parent 左or右
        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);  //通过compare 比较节点以及判相同
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value); // compare相同  则判定找对位置 直接覆盖(不可重复)
            } while (t != null);
        }
        //没有 指定排序调用自然排序 comparable 进行比较 key不可为null
        else {
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                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);
        //根据cmp  确定当前节点位置
        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;
				// 跳出循环条件 
        // 1 当前节点为null 
        // 2 当前节点为根节点
        // 3 当前节点的父节点为黑色
        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));
                // 叔叔为黑色(这种情况只能为叔叔节点不存在为nil)
                } 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;
    }

删除节点:

	// 根据key删除节点
    public V remove(Object key) {
    		// 获取key对应的 Entry
        Entry<K,V> p = getEntry(key);
        // 如果entry 为null 直接返回null
        if (p == null)
            return null;
				// 原value 作为返回值返回
        V oldValue = p.value;
        // 执行删除entry  并调整树结构
        deleteEntry(p);
        return oldValue;
    }

真正删除节点方法:

deleteEntry:

		/**
     * Delete node p, and then rebalance the tree.
     */
    private void deleteEntry(Entry<K,V> p) {
        modCount++; // 修改次数加1
        size--;     // 数目减1

        // If strictly internal, copy successor's element to p and then make p
        // point to successor.
        // p左右节点均不为null 
        // 找到比p大 且数值最接近的 节点  并 赋值给p
        if (p.left != null && p.right != null) {
        		//  找 比传入节点大 且最接近的 节点   找p节点的后继节点
            Entry<K,V> s = successor(p);
            // 将待删除节点设置为 successor节点的key  value   让后继取代p
            p.key = s.key; 
            p.value = s.value;
            p = s; //待删除节点设置为 后继节点
        } // p has 2 children
				
        // Start fixup at replacement node, if it exists.
        // 获取节点的 非null孩子
        Entry<K,V> replacement = (p.left != null ? p.left : p.right);
				// 存在不为null 的孩子  
        if (replacement != null) {
            // Link replacement to parent
            replacement.parent = p.parent; //更新孩子节点 父引用
            //p节点为 根节点
            if (p.parent == null)
                root = replacement;
            //p为左子节点  更新父节点左子
            else if (p == p.parent.left) 
                p.parent.left  = replacement;
            else
                p.parent.right = replacement;

            // Null out links so they are OK to use by fixAfterDeletion.
            p.left = p.right = p.parent = null; //help gc

            // Fix replacement
            // 如待删除节点为黑色  进行调整
            if (p.color == BLACK)
                fixAfterDeletion(replacement);
        // 孩子皆null  且父为null  说明 树仅有一个根节点
        } else if (p.parent == null) { // return if we are the only node.
            root = null;  //  根节点置为null
        //  孩子皆null  且父不为null  说明是叶子节点
        } else { //  No children. Use self as phantom replacement and unlink.
        		// 当前节点是黑色节点  调整树
            if (p.color == BLACK)
                fixAfterDeletion(p);
						// 更新父节点对  孩子的引用
            if (p.parent != null) {	
                if (p == p.parent.left)
                    p.parent.left = null;
                else if (p == p.parent.right)
                    p.parent.right = null;
                p.parent = null; //更新孩子 对父亲的引用
            }
        }
    }

successor

	/**
     * Returns the successor of the specified Entry, or null if no such.
     */
    //  找 比传入节点大 且最接近的 节点
    static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
        if (t == null)
            return null;
        //右面节点不为null  找到右节点的最左节点 上位
        else if (t.right != null) {
            Entry<K,V> p = t.right;
            while (p.left != null)
                p = p.left;
            return p;
        // 右节点为null 
        } else {
        		// 拿到父节点
            Entry<K,V> p = t.parent;
            Entry<K,V> ch = t; // 当前节点
            while (p != null && ch == p.right) {
                ch = p;
                p = p.parent;
            }
            return p;
        }
    }

如待删除节点为 黑色节点 需要调整树结构

调用fixAfterDeletion方法:

/** From CLR */
    private void fixAfterDeletion(Entry<K,V> x) {
    		// 当前节点为根节点   或   当前节点颜色为 红色  跳出循环
        while (x != root && colorOf(x) == BLACK) {
        		// 如果 x是父节点的  左孩子
            if (x == leftOf(parentOf(x))) {
            		// 拿到右兄弟节点
                Entry<K,V> sib = rightOf(parentOf(x));
								// 如果兄弟节点为红色  说明父节点为黑色
                if (colorOf(sib) == RED) {
                		//兄弟设置为黑色
                    setColor(sib, BLACK);
                    // 父 设置为红色
                    setColor(parentOf(x), RED);
                    // 父节点左旋
                    rotateLeft(parentOf(x));
                    // 拿到旋转后的新兄弟节点  为黑色
                    sib = rightOf(parentOf(x));
                }
								// 如果兄弟节点左孩子颜色为 黑色 且 兄弟节点右孩子为 黑色
                if (colorOf(leftOf(sib))  == BLACK &&
                    colorOf(rightOf(sib)) == BLACK) {
                    // 设置兄弟节点为 红色
                    setColor(sib, RED);
                    // 将父节点赋值给 当前节点
                    x = parentOf(x);
                } else {
                    // 兄弟节点仅右节点为黑色  左节点为红色
                    if (colorOf(rightOf(sib)) == BLACK) {
                        setColor(leftOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateRight(sib);
                        sib = rightOf(parentOf(x));
                    }
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(rightOf(sib), BLACK);
                    rotateLeft(parentOf(x));
                    x = root;
                }
            // 如果 x是父节点的  右孩子
            } else { // symmetric
                Entry<K,V> sib = leftOf(parentOf(x));

                if (colorOf(sib) == RED) {
                    setColor(sib, BLACK);
                    setColor(parentOf(x), RED);
                    rotateRight(parentOf(x));
                    sib = leftOf(parentOf(x));
                }

                if (colorOf(rightOf(sib)) == BLACK &&
                    colorOf(leftOf(sib)) == BLACK) {
                    setColor(sib, RED);
                    x = parentOf(x);
                } else {
                    if (colorOf(leftOf(sib)) == BLACK) {
                        setColor(rightOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateLeft(sib);
                        sib = leftOf(parentOf(x));
                    }
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(leftOf(sib), BLACK);
                    rotateRight(parentOf(x));
                    x = root;
                }
            }
        }

        setColor(x, BLACK);
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值