HashSet类包含一个数组table和一个整数size,用于存储元素和记录元素个数。HashSet类还包含添加元素、删除元素和查找元素的方法。Entry类表示HashSet中的每个元素,包含一个元素和一个指向下一个节点的引用。HashSet类和Entry类之间存在关联关系。
在这篇博客中,我们将手写一个HashSet类,实现HashSet的基本操作,包括添加元素、删除元素、查找元素等。
首先,我们需要创建一个名为HashSet的类,该类将实现HashSet的基本操作。
public class HashSet<E> {
private static final int DEFAULT_CAPACITY = 16;
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
private Entry<E>[] table;
private int size;
public HashSet() {
table = new Entry[DEFAULT_CAPACITY];
size = 0;
}
// 其他操作
}
在HashSet类中,我们使用一个数组来存储元素,每个数组元素是一个链表的头节点。我们还使用一个变量size来记录HashSet中的元素个数。
接下来,我们需要实现一个散列函数,将元素映射到数组的索引位置。
private int hash(E element) {
return element.hashCode() % table.length;
}
在这个散列函数中,我们使用元素的hashCode方法来获取散列码,然后使用取余运算符将散列码映射到数组的索引位置。
接下来,我们将实现向HashSet中添加元素的操作。
public boolean add(E element) {
int index = hash(element);
Entry<E> current = table[index];
while (current != null) {
if (current.element.equals(element)) {
return false;
}
current = current.next;
}
Entry<E> newEntry = new Entry<>(element);
newEntry.next = table[index];
table[index] = newEntry;
size++;
return true;
}
在这个操作中,我们首先使用散列函数计算元素的索引位置。然后,我们遍历该索引位置的链表,如果找到与要添加的元素相等的元素,则返回false。否则,我们创建一个新的Entry对象,并将其插入链表的头部,然后更新数组的对应位置和HashSet的元素个数。
接下来,我们将实现从HashSet中删除元素的操作。
public boolean remove(E element) {
int index = hash(element);
Entry<E> current = table[index];
Entry<E> prev = null;
while (current != null) {
if (current.element.equals(element)) {
if (prev == null) {
table[index] = current.next;
} else {
prev.next = current.next;
}
size--;
return true;
}
prev = current;
current = current.next;
}
return false;
}
在这个操作中,我们首先使用散列函数计算元素的索引位置。然后,我们遍历该索引位置的链表,找到与要删除的元素相等的元素,将其从链表中移除,并更新数组的对应位置和HashSet的元素个数。
接下来,我们将实现从HashSet中查找元素的操作。
public boolean contains(E element) {
int index = hash(element);
Entry<E> current = table[index];
while (current != null) {
if (current.element.equals(element)) {
return true;
}
current = current.next;
}
return false;
}
在这个操作中,我们首先使用散列函数计算元素的索引位置。然后,我们遍历该索引位置的链表,找到与要查找的元素相等的元素,返回true。如果遍历完链表仍未找到相等的元素,则返回false。
为了存储元素和构建链表,我们需要实现一个名为Entry的内部类。
private static class Entry<E> {
E element;
Entry<E> next;
public Entry(E element) {
this.element = element;
this.next = null;
}
}
Entry类包含一个元素和一个指向下一个节点的引用。
通过以上步骤,我们成功实现了一个简单的HashSet类。它基于散列(Hash)实现,使用数组和链表来存储元素。我们实现了添加元素、删除元素、查找元素等基本操作。
这个手写的HashSet类可以作为学习和理解HashSet的实现原理的基础。我们可以进一步扩展它,添加更多的功能和优化性能。
假设我们有一个电话号码黑名单,我们希望实现一个电话号码过滤器,能够根据黑名单中的电话号码来过滤输入的电话号码。我们可以使用HashSet来存储黑名单中的电话号码,并使用HashSet的contains方法来判断输入的电话号码是否在黑名单中。
import java.util.HashSet;
public class PhoneNumberFilter {
private HashSet<String> blacklist;
public PhoneNumberFilter() {
blacklist = new HashSet<>();
}
public void addPhoneNumber(String phoneNumber) {
blacklist.add(phoneNumber);
}
public void removePhoneNumber(String phoneNumber) {
blacklist.remove(phoneNumber);
}
public boolean isPhoneNumberBlocked(String phoneNumber) {
return blacklist.contains(phoneNumber);
}
}
在这个例子中,我们使用HashSet来存储黑名单中的电话号码。我们可以使用addPhoneNumber方法将电话号码添加到黑名单中,使用removePhoneNumber方法将电话号码从黑名单中移除,使用isPhoneNumberBlocked方法来判断输入的电话号码是否在黑名单中。
这个例子展示了HashSet的一种实际应用,通过使用HashSet来存储数据,我们可以快速地进行查找和判断操作,从而实现高效的数据过滤功能。