📅  最后修改于: 2023-12-03 15:25:09.553000             🧑  作者: Mango
LinkedHashSet 是 Java 集合框架中的一个类,它继承自 HashSet,内部使用链表维护元素的顺序。相比于 HashSet,LinkedHashSet 能够保持元素的插入顺序,而且元素在遍历时会按照插入顺序进行。
这篇文章将介绍如何通过 Java 代码实现 LinkedHashSet 的主要 API,即 add、remove、contains 和 iterator。我们将从零开始,一步步地构建 LinkedHashSet 类。
LinkedHashSet 的实现基于哈希表,使用桶(bucket)存储元素。每个桶包含一个链表,链表中的每个节点都包含一个元素和指向下一个节点的引用。
在插入元素时,我们需要先计算出元素的哈希值并对桶的数量取模,得到该元素所对应的桶的索引。然后,我们将元素插入到对应桶的链表的末尾。
在查找元素时,我们需要先计算出元素的哈希值并对桶的数量取模,得到该元素所对应的桶的索引。然后,我们遍历对应桶的链表,查找是否存在与该元素相同的元素。
在删除元素时,我们需要先计算出元素的哈希值并对桶的数量取模,得到该元素所对应的桶的索引。然后,我们遍历对应桶的链表,查找是否存在与该元素相同的元素。如果找到了,我们就删除该元素所在的节点。
在遍历元素时,我们需要依次访问每个桶,然后遍历每个桶中链表的每个节点,返回元素的顺序即可。
现在,我们来一步步实现 LinkedHashSet 的主要 API。
在实现 LinkedHashSet 时,我们需要定义一个 Node 类来表示链表中的节点。每个节点包含一个元素和指向下一个节点的引用。这里我们定义的 Node 类是一个泛型类,它具有一个元素值 E 和一个指向下一个节点的 Node 引用 next:
public class Node<E> {
E element;
Node<E> next;
public Node(E element) {
this.element = element;
this.next = null;
}
public E getElement() {
return element;
}
public void setElement(E element) {
this.element = element;
}
public Node<E> getNext() {
return next;
}
public void setNext(Node<E> next) {
this.next = next;
}
}
接下来,我们需要定义 LinkedHashSet 类。在这个类中,我们需要定义一个 Node 类型的数组 buckets,用于存储元素。我们还需要定义一个整型变量 size,表示集合中元素的数量。
public class LinkedHashSet<E> {
private Node<E>[] buckets;
private int size;
}
LinkedHashSet 类包含一个默认构造函数和一个带初始容量和负载因子的构造函数。默认构造函数创建一个大小为 16 的桶数组,负载因子为 0.75。带初始容量和负载因子的构造函数可以根据需要调整桶数组的大小。
LinkedHashSet 还包含一个 add 方法,用于向集合中添加元素。在这个方法中,我们需要根据元素的哈希值得出桶的索引,然后遍历该桶的每个节点,查找是否存在与该元素相同的元素。
如果不存在,则将该元素插入到对应的节点的末尾。插入时,需要创建一个新的节点,并将其插入到链表的末尾。如果存在,则不进行任何操作。
以下是 LinkedHashSet 类的代码:
public class LinkedHashSet<E> {
private Node<E>[] buckets;
private int size;
public LinkedHashSet() {
this(16, 0.75f);
}
@SuppressWarnings("unchecked")
public LinkedHashSet(int initialCapacity, float loadFactor) {
buckets = (Node<E>[]) new Node[initialCapacity];
size = 0;
}
public boolean add(E element) {
int hash = element.hashCode();
int index = hash % buckets.length;
Node<E> node = buckets[index];
while (node != null) {
if (node.element.equals(element)) {
return false;
}
node = node.next;
}
Node<E> newNode = new Node<>(element);
newNode.next = buckets[index];
buckets[index] = newNode;
size++;
return true;
}
}
LinkedHashSet 类还包含一个 remove 方法,用于从集合中删除元素。在这个方法中,我们需要遍历对应桶的链表,查找是否存在与该元素相同的元素。如果找到了,我们就删除该元素所在的节点,并返回 true。如果找不到,则返回 false。
LinkedHashSet 类还包含一个 contains 方法,用于判断集合中是否包含某个元素。在这个方法中,我们需要遍历对应桶的链表,查找是否存在与该元素相同的元素。如果找到了,就返回 true。如果找不到,则返回 false。
以下是 LinkedHashSet 类的完整代码:
public class LinkedHashSet<E> {
private Node<E>[] buckets;
private int size;
public LinkedHashSet() {
this(16, 0.75f);
}
@SuppressWarnings("unchecked")
public LinkedHashSet(int initialCapacity, float loadFactor) {
buckets = (Node<E>[]) new Node[initialCapacity];
size = 0;
}
public boolean add(E element) {
int hash = element.hashCode();
int index = hash % buckets.length;
Node<E> node = buckets[index];
while (node != null) {
if (node.element.equals(element)) {
return false;
}
node = node.next;
}
Node<E> newNode = new Node<>(element);
newNode.next = buckets[index];
buckets[index] = newNode;
size++;
return true;
}
public boolean remove(E element) {
int hash = element.hashCode();
int index = hash % buckets.length;
Node<E> node = buckets[index];
Node<E> prev = null;
while (node != null) {
if (node.element.equals(element)) {
if (prev == null) {
buckets[index] = node.next;
} else {
prev.next = node.next;
}
size--;
return true;
}
prev = node;
node = node.next;
}
return false;
}
public boolean contains(E element) {
int hash = element.hashCode();
int index = hash % buckets.length;
Node<E> node = buckets[index];
while (node != null) {
if (node.element.equals(element)) {
return true;
}
node = node.next;
}
return false;
}
}
最后,我们需要实现 iterator 方法,用于遍历集合中的元素。在这个方法中,我们需要依次访问每个桶,然后遍历每个桶中链表的每个节点,按照插入顺序返回元素的值。
以下是 iterator 方法的实现:
public Iterator<E> iterator() {
return new Iterator<E>() {
private int bucket = 0;
private Node<E> node = buckets[bucket];
public boolean hasNext() {
while (node == null) {
bucket++;
if (bucket >= buckets.length) {
return false;
}
node = buckets[bucket];
}
return true;
}
public E next() {
E result = node.element;
node = node.next;
if (node == null) {
bucket++;
if (bucket < buckets.length) {
node = buckets[bucket];
}
}
return result;
}
};
}
我们已经实现了 LinkedHashSet 的主要 API,包括 add、remove、contains 和 iterator 方法。虽然这个过程比较繁琐,但是通过一步步实现,我们可以更好地理解 LinkedHashSet 的工作原理。
LinkedHashSet 是一个非常有用的集合类,它能够保持元素的插入顺序,并且在遍历时按照插入顺序进行。掌握 LinkedHashSet 的使用和实现可以帮助我们更好地理解 Java 集合框架。