JAVA数据结构篇--12理解LinkedHashSet&TreeSet

前言:在java 中使用HashSet 结构来存放不重复的元素,但是HashSet 内部的元素时乱序的,存入和取出元素的顺序不能保证,那么有没有一种结构可以保证其顺序性,或者使用者可以自行决定顺序;LinkedHashSet 即实现了存取顺序的一致性;TreeSet可以让开发者自己定义元素的比较器,自行决定顺序;

1 使用:

// LinkedHashSet
Set<User> set = new LinkedHashSet<>(10, 0.75f);
 User userOne = new User();
 userOne.setId(1).setName("lisi").setAge(20);
 set.add(userOne);
 User userTwo = new User();
 userTwo.setId(2).setName("wangwu").setAge(20);
 set.add(userTwo);
 set.remove(userTwo);

 Iterator iterator1 = set.iterator();
 while (iterator1.hasNext()) {
     User user = (User) iterator1.next();
     System.out.println("user = " + user);
 }
//  TreeSet
 Set<User> set1 = new TreeSet<>(Comparator.comparingInt(User::getId));
 User user1 = new User();
 user1.setId(1).setName("lisi").setAge(20);

 set1.add(userOne);
 set1.add(userTwo);
 set1.remove(userTwo);
 Iterator iterator2 = set1.iterator();
 while (iterator2.hasNext()) {
     User user = (User) iterator2.next();
     System.out.println("user = " + user);
 }

2 过程:
2.1 构建:
LinkedHashSet:可以看到内部实际使用了LinkedHashMap进行数据存放

    public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
    }
    public LinkedHashSet(int initialCapacity) {
        super(initialCapacity, .75f, true);
    }
    public LinkedHashSet() {
        super(16, .75f, true);
    }
    public LinkedHashSet(Collection<? extends E> c) {
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
    }
    // 使用HashSet 中 LinkedHashMap 作为数据结构进行存放
   HashSet(int initialCapacity, float loadFactor, boolean dummy) {
       map = new LinkedHashMap<>(initialCapacity, loadFactor);
   }

TreeSet:可以看到内部实际上使用TreeMap 进行数据存放

private transient NavigableMap<E,Object> m;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();
    TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }
    public TreeSet() {
        this(new TreeMap<E,Object>());
    }
    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }
    public TreeSet(Collection<? extends E> c) {
        this();
        addAll(c);
    }
    public TreeSet(SortedSet<E> s) {
        this(s.comparator());
        addAll(s);
    }

2.2 存入元素:
2.2.1 LinkedHashSet: 使用 LinkedHashMap 将元素e作为key ,new object() 作为value 进行数据存入

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

2.2.2 treeSet:使用 TreeMap 将元素e作为key ,new object() 作为value 进行数据存入

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

2.3 移除元素:
2.3.1 LinkedHashSet: 将元素从 LinkedHashMap 移除

public boolean remove(Object o) {
      return map.remove(o)==PRESENT;
  }

2.3.2 treeSet: 将元素从 TreeMap 移除

public boolean remove(Object o) {
       return m.remove(o)==PRESENT;
   }

2.4 遍历元素:
2.4.1 LinkedHashSet:获取LinkedHashMap的keySet进行遍历:

public Iterator<E> iterator() {
     return map.keySet().iterator();
 }
final class LinkedKeySet extends AbstractSet<K> {
    public final int size()                 { return size; }
    public final void clear()               { LinkedHashMap.this.clear(); }
    public final Iterator<K> iterator() {
        return new LinkedKeyIterator();
    }
    public final boolean contains(Object o) { return containsKey(o); }
    public final boolean remove(Object key) {
        return removeNode(hash(key), key, null, false, true) != null;
    }
    public final Spliterator<K> spliterator()  {
        return Spliterators.spliterator(this, Spliterator.SIZED |
                                        Spliterator.ORDERED |
                                        Spliterator.DISTINCT);
    }
    public final void forEach(Consumer<? super K> action) {
        if (action == null)
            throw new NullPointerException();
        int mc = modCount;
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
            action.accept(e.key);
        if (modCount != mc)
            throw new ConcurrentModificationException();
    }
}
final class LinkedKeyIterator extends LinkedHashIterator
    implements Iterator<K> {
    public final K next() { return nextNode().getKey(); }
}
final LinkedHashMap.Entry<K,V> nextNode() {
   LinkedHashMap.Entry<K,V> e = next;
   if (modCount != expectedModCount)
       throw new ConcurrentModificationException();
   if (e == null)
       throw new NoSuchElementException();
   current = e;
   next = e.after;
   return e;
}

2.4.2:treeSet

 public Iterator<E> iterator() {
  return m.navigableKeySet().iterator();
}
// TreeMap KeySet
 public Iterator<E> iterator() {
    if (m instanceof TreeMap)
        return ((TreeMap<E,?>)m).keyIterator();
    else
        return ((TreeMap.NavigableSubMap<E,?>)m).keyIterator();
}
Iterator<K> keyIterator() {
	return new KeyIterator(getFirstEntry());
}
final class KeyIterator extends PrivateEntryIterator<K> {
    KeyIterator(Entry<K,V> first) {
        super(first);
    }
    public K next() {
        return nextEntry().key;
    }
}
Entry<K,V> next;
Entry<K,V> lastReturned;
int expectedModCount;

PrivateEntryIterator(Entry<K,V> first) {
    expectedModCount = modCount;
    lastReturned = null;
    next = first;
}
// first 节点获取
final Entry<K,V> getFirstEntry() {
    Entry<K,V> p = root;
    if (p != null)
        while (p.left != null)
            p = p.left;
    return p;
}
// 下一节点获取
final Entry<K,V> nextEntry() {
    Entry<K,V> e = next;
    if (e == null)
        throw new NoSuchElementException();
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    next = successor(e);
    lastReturned = e;
    return e;
}
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;
    }
}

3 总结
3.1 LinkedHashSet 内部使用LinkedHashMap 将元素e 作为key 进行数据存放;TreeSet 内部使用TreeMap 将元素e 作为key 进行数据存放;
3.2 因为LinkedHashMap 内部元素通过prev 和next 指针维护了元素的有些性,进而保证了LinkedHashSet 存取元素的有序性;TreeSet 通过TreeMap 使用红黑树形结构,通过自定义元素的比较器 来保证元素存取元素的有序性;
3.3 LinkedHashSet&TreeSet 都不是线程安全的;

你可能感兴趣的:(java基础篇,java工具篇,数据结构,java,开发语言)