java源码解读之TreeMap------jdk 1.7

引自网上:TreeMap是基于红黑树结构实现的一种Map,要分析TreeMap的实现首先就要对红黑树有所了解。
红黑树简单说就是一个顶部节点,大于等于这个节点的放在右边,小于等于这个节点的放在左边。
红黑树需要遵守的规则:
1.每个节点要么是红色,要么是黑色。
2.根节点必须是黑色
3.红色节点不能连续(也即是,红色节点的孩子和父亲都不能是红色)。
4.对于每个节点,从该点至null(树尾端)的任何路径,都含有相同个数的黑色节点。

如下图:
这里写图片描述

1. 定义
//其他就不说了,主要说说NavigableMap
public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
//关于NavigableMap具体可以看http://blog.csdn.net/jackyrongvip/article/details/9218803
public interface NavigableMap<K,V> extends SortedMap<K,V> 
2. 属性
//比较器,用于排序
private final Comparator<? super K> comparator;
//根节点
private transient Entry<K,V> root = null;
//总元素数量
private transient int size = 0;
//修改次数
private transient int modCount = 0;
3. 构造器
//默认排序,要求key自己实现comparator接口
public TreeMap() {
    comparator = null;
}
//传入比较器,按照比较器实现排序
public TreeMap(Comparator<? super K> comparator) {
    this.comparator = comparator;
}
//传入初始数据,默认排序
public TreeMap(Map<? extends K, ? extends V> m) {
    comparator = null;
    putAll(m);
}
//根据传入的SortedMap构建TreeMap
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) {
    }
}
private void buildFromSorted(int size, Iterator it,
                             java.io.ObjectInputStream str,
                             V defaultVal)
    throws  java.io.IOException, ClassNotFoundException {
    //赋值size,跟HashMap不同,不需要保证size为2的n次方
    this.size = size;
    //创建红黑树
    root = buildFromSorted(0, 0, size-1, computeRedLevel(size),
                           it, str, defaultVal);

}
//计算树应该有多少高
private static int computeRedLevel(int sz) {
    int level = 0;
    //(sz - 1)是为了从零开始循环
    for (int m = sz - 1; m >= 0; m = m / 2 - 1)
        level++;
    return level;
}
//因为传入的sortmap是已经排序过的,所以下方直接比较排序号就可以了
private final Entry<K,V> buildFromSorted(int level, int lo, int hi,
                                         int redLevel,
                                         Iterator it,
                                         java.io.ObjectInputStream str,
                                         V defaultVal)
    throws  java.io.IOException, ClassNotFoundException {
    if (hi < lo) return null;
    //计算
    int mid = (lo + hi) >>> 1;

    Entry<K,V> left  = null;
    // 成立说明lo应该放在左边
    if (lo < mid)
        left = buildFromSorted(level+1, lo, mid - 1, redLevel,
                               it, str, defaultVal);

    // extract key and/or value from iterator or stream
    K key;
    V value;
    //根据传入参数获得key和value
    //如果迭代器不为null,则使用迭代器获得
    if (it != null) {
        if (defaultVal==null) {
            Map.Entry<K,V> entry = (Map.Entry<K,V>)it.next();
            key = entry.getKey();
            value = entry.getValue();
        } else {
            key = (K)it.next();
            value = defaultVal;
        }
    //否则使用流来获得entry
    } else {
        key = (K) str.readObject();
        value = (defaultVal != null ? defaultVal : (V) str.readObject());
    }
    //根据key和value创建一个entry
    Entry<K,V> middle =  new Entry<>(key, value, null);
    // 如果高度跟预计高度一致,把中间节点染成红色
    if (level == redLevel)
        middle.color = RED;
    //如果左边节点不为null,那就把left(也就是上方的lo)放在middle的左边,并且把left的父节点设置为middle
    if (left != null) {
        middle.left = left;
        left.parent = middle;
    }
    //成立说明hi要放在右边
    if (mid < hi) {
        Entry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel,
                                           it, str, defaultVal);
        //同上,不同的地方在于放在右边
        middle.right = right;
        right.parent = middle;
    }
    //返回中间节点
    return middle;
}

这里写图片描述

4.解析部分方法源码

4.1 增加方法
public V put(K key, V value) {
    Entry<K,V> t = root;
    if (t == null) {
        //比较方法,可以校验key是否为null,如果为null报NullPointerException
        compare(key, key);
        //创建一个新的节点赋值给根节点
        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        return null;
    }
    //记录比较结果
    int cmp;
    //父节点
    Entry<K,V> parent;
    //分割比较器和可比较接口的处理
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        do {
            parent = t;
            cmp = cpr.compare(key, t.key);
            //根据比较结果决定向左查找还是向右查找,直到相等或者t被赋值为null
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    else {
        //使用key对象自带的比较器进行比较
        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;
    //对加入新节点的树进行调整,染色,详细了解可看http://www.cnblogs.com/CarpenterLee/p/5525688.html
    fixAfterInsertion(e);
    size++;
    modCount++;
    return null;
}
//调用比较器获得比较结果
final int compare(Object k1, Object k2) {
    return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
        : comparator.compare((K)k1, (K)k2);
}
public void putAll(Map<? extends K, ? extends V> map) {
    //获得传入map的size
    int mapSize = map.size();
    //如果类型是SortedMap或者他的实现类,调用buildFromSorted放置map
    if (size==0 && mapSize!=0 && map instanceof SortedMap) {
        Comparator c = ((SortedMap)map).comparator();
        if (c == comparator || (c != null && c.equals(comparator))) {
            ++modCount;
            try {
                buildFromSorted(mapSize, map.entrySet().iterator(),
                                null, null);
            } catch (java.io.IOException cannotHappen) {
            } catch (ClassNotFoundException cannotHappen) {
            }
            return;
        }
    }
    //否则调用父类的方法遍历之后调用put方法存放
    super.putAll(map);
}
//以下就是上方调用的父类的putAll方法
public void putAll(Map<? extends K, ? extends V> m) {
    for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
        put(e.getKey(), e.getValue());
}
4.2 删除方法
public V remove(Object key) {
    //根据key获得对应entry
    Entry<K,V> p = getEntry(key);
    if (p == null)
        return null;

    V oldValue = p.value;
    //删除节点的核心方法封装在这个方法里面
    deleteEntry(p);
    //返回旧值
    return oldValue;
}
final Entry<K,V> getEntry(Object key) {
    // 如果比较器不为空,通过比较器进行查找
    if (comparator != null)
        return getEntryUsingComparator(key);
    if (key == null)
        throw new NullPointerException();
    //否则通过key自身的比较器进行查找
    Comparable<? super K> k = (Comparable<? super K>) key;
    Entry<K,V> p = root;
    while (p != null) {
        int cmp = k.compareTo(p.key);
        if (cmp < 0)
            p = p.left;
        else if (cmp > 0)
            p = p.right;
        else
            return p;
    }
    return null;
}
//通过比较器查找相等的entry
final Entry<K,V> getEntryUsingComparator(Object key) {
    K k = (K) key;
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        Entry<K,V> p = root;
        while (p != null) {
            int cmp = cpr.compare(k, p.key);
            if (cmp < 0)
                p = p.left;
            else if (cmp > 0)
                p = p.right;
            else
                return p;
        }
    }
    return null;
}
private void deleteEntry(Entry<K,V> p) {
    modCount++;
    size--;

    // 如果左右子节点都不为null
    if (p.left != null && p.right != null) {
        //寻找替代节点
        Entry<K,V> s = successor(p);
        //把p替换成替代节点
        p.key = s.key;
        p.value = s.value;
        p = s;
    } 

    // 上面处理过之后,现在要么是左节点是null,要么是右节点是null,要么左右节点均为null
    Entry<K,V> replacement = (p.left != null ? p.left : p.right);

    //把p的与其他节点之间的关联清空
    //删除点p只有一棵子树非空
    if (replacement != null) {
        //假设有1,2,3三个节点,相当于2不要,直接让1和3连线
        replacement.parent = p.parent;
        //如果p的父节点为null,那就跟root连在一起
        if (p.parent == null)
            root = replacement;
        //否则原来应该是放在哪一边的,现在还是放在哪一边
        else if (p == p.parent.left)
            p.parent.left  = replacement;
        else
            p.parent.right = replacement;
        //清空p的关联关系,让gc更快回收的意思吧
        p.left = p.right = p.parent = null;
        //如果删除的是黑节点就违反了上方的规则4,需要重新调整红黑树结构与颜色
        if (p.color == BLACK)
            fixAfterDeletion(replacement);//调整
    // return if we are the only node.
    //如果只有一个节点的情况,作用就像上方的英文表达的意思
    } else if (p.parent == null) {
        root = null;
    } else {
        //  No children. Use self as phantom replacement and unlink.
        //删除点p的左右子树都为空
        //违反规则4需要调整
        if (p.color == BLACK)
            fixAfterDeletion(p);
        //如果父节点不为null
        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;
        }
    }
}
static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
    if (t == null)
        return null;
    // 查找右子树的最左孩子
    else if (t.right != null) {
        Entry<K,V> p = t.right;
        while (p.left != null)
            p = p.left;
        return p;
    } 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;
    }
}
4.3 修改方法
就是put同样的key就能覆盖value.

4.4 查找方法
public V get(Object key) {
    //上面已介绍过,不多说
    Entry<K,V> p = getEntry(key);
    return (p==null ? null : p.value);
}
4.5 迭代器
//调用是父类的迭代器,关键在于这个获得第一个的方法
final Entry<K,V> getFirstEntry() {
    //获得最左边的节点
    Entry<K,V> p = root;
    if (p != null)
        while (p.left != null)
            p = p.left;
    return p;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值