TreeSet是怎么实现去重的

Scroll Down

当这个问题第一时间问到我的时候,我以为TreeSet跟HashSet一样,底层都是通过hashMap来实现,后面发现其实不是,今天我们就来走一走TreeSet的底层源码。

运行版本:JDK1.8

首先看一下TreeSet的无参构造器,可以看到是TreeMap,没用到HashMap。

 public TreeSet() {
        this(new TreeMap<E,Object>());
    }

这段代码又调用了一个新的构造器,我们往里面走了看一下。

TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }

将新创建出来的TreeMap对象赋值给了对象属性m,NavigableMap这是一个接口,具体的目前还没有了解过,我们先继续往下面走。

我们要想看到他怎么去重的,直接就去看他的add方法:

public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }

直接调用的是TreeMap的put方法,我们直接去看TreeMap源码

public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
//对key做处理,检查是否为null
            compare(key, key); // type (and possibly null) check
//给root赋值
            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
//key对比结果
        int cmp;
        Entry<K,V> parent;
// split comparator and comparable paths
//比较器,如果我们在创建TreeMap的时候可以自定义一个比较器传入到里面
        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 {
//如果传进来的key为空,直接抛出异常
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                Comparable<? super K> k = (Comparable<? super K>) key;
//下面这个while循环是用来给key找到他在树中的位置
//如果有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);
//如果在树种不存在key则,将新key插入树中
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
//红黑树处理
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }

根据源码分析可以得到,TreeMap底层的数据结构是一个红黑树,如果新增一个key进来,首先会判断这key的值在树中是否存在,若存在则替换掉,若不存在则插入其中。