HashSet
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable
特征
基于HashMap实现,无容量限制
不保证集合的迭代顺序(顺序依据hash值)
允许空元素(null),但只能放入一个null
实现不同步(线程不安全)
如果在创建迭代器后的任何时间修改集合,则除了通过迭代器自己的 remove 方法之外,都throw
数据结构
哈希表
//由哈希表(实际上是 HashMap 实例)提供支持
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
//用于与底层map中的对象关联
private static final Object PRESENT = new Object();
构造方法
//无参构造
public HashSet() {
map = new HashMap<>();
}
//有参构造(初始容量)
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
//有参(初始容量, hash映射的负载系数) 后面会说loadFactor(此处可忽略)
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
添加操作
//元素E作为map集合中的Key值, key值不唯一
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
删除操作
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
遍历操作
//获取迭代器
public Iterator<E> iterator() {
return map.keySet().iterator();
}
//通过循环遍历每一个元素
while (iterator.hasNext()){
Object element= iterator.next();
}
使用场景
按照Hash算法来实现元素的查找和存储的
去重、快速查找或随机元素
去重
需要重写对象的equals和hashCode
注意:如果只重写equls方法, 不重写hashCode方法, 在HashSet去重中,最终的HashSet中应该只保留1个对象,即最终输出的HashSet的size为1,但是我们得到的结果却是2
快速查找
由于HashSet的元素是经过哈希计算的,因此可以通过哈希表快速进行查找操作
随机元素
由于HashSet中的元素是无序的,因此可以通过随机获取HashSet中的元素来实现随机数的操作
Set setOfNumbers = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
int randomIndex = new Random().nextInt(setOfNumbers.size());
Iterator iterator = setOfNumbers.iterator();
int i = 0;
while(iterator.hasNext()){
int number = iterator.next();
if (i == randomIndex){
System.out.println("Random number: " + number);
break;
}
i++;
}
//参考: https://www.zhihu.com/question/401606017
TreeSet
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable
特征
不允许空元素(null)
元素有序(排序)
实现不同步(线程不安全)
数据结构
红黑树(平衡二叉树)
//map
private transient NavigableMap<E,Object> m;
// Dummy value to associate with an Object in the backing Map
//同HashSet的PRESENT
private static final Object PRESENT = new Object();
构造方法
//无参构造
public TreeSet() {
this(new TreeMap<E,Object>());
}
//有参构造(比较器)
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
(1)无参方法中, 比较器为null.
Element 类 可以通过实现Comparable接口, 重写compareTo()方法实现排序
compareTo返回值 1是前者权重大,-1是后者权重大。按照权重由小到大排序
this在前表示升序
o在前表示降序
this.成员变量1.compareTo(o.成员变量1) == 0 ?
this.成员变量2.compareTo(o.成员变量2) :
this.成员变量1.compareTo(o.成员变量1)
//表示首排序为成员变量1, 次排序为成员变量2.
举例: return this.id.compareTo(student.id) == 0 ? this.name.compareTo(student.name) : this.id.compareTo(student.id);
(2)有参方法中使用Compatator的匿名内部类, 实现compare(O1, O2)方法
o1 - o2 升序
o2 - o1 降序
添加操作
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
//
public boolean addAll(Collection<? extends E> c) {
// Use linear-time version if applicable
if (m.size()==0 && c.size() > 0 &&
c instanceof SortedSet &&
m instanceof TreeMap) {
SortedSet<? extends E> set = (SortedSet<? extends E>) c;
TreeMap<E,Object> map = (TreeMap<E, Object>) m;
Comparator<?> cc = set.comparator();
Comparator<? super E> mc = map.comparator();
if (cc==mc || (cc != null && cc.equals(mc))) {
map.addAllForTreeSet(set, PRESENT); //map方法
return true;
}
}
return super.addAll(c);
}
删除操作
public boolean remove(Object o) {
return m.remove(o)==PRESENT;
}
遍历操作
public Iterator<E> iterator() {
return m.navigableKeySet().iterator();
}
使用场景
排序, 元素需要排序使用TreeSet
LinkedHashSet
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, java.io.Serializable
特征
具有迭代顺序
实现不同步(线程不安全)
继承自HashSet, 底层是LinkedHashMap
没有重复的元素
数据结构
哈希表和双向链表实现
构造方法
//无参构造
public LinkedHashSet() {
super(16, .75f, true);
}
//有参构造(初始化容量)
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
//有参构造(初始化容量, 负载因子)
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}