手写HashSet的实现和拓展

手写HashSet的实现

思维导图:

HashSet类包含一个数组table和一个整数size,用于存储元素和记录元素个数。HashSet类还包含添加元素、删除元素和查找元素的方法。Entry类表示HashSet中的每个元素,包含一个元素和一个指向下一个节点的引用。HashSet类和Entry类之间存在关联关系。

HashSet
- table: Entry[]
- size: int
+add(element: E)
+remove(element: E)
+contains(element: E)
-hash(element: E)
Entry
- element: E
- next: Entry

在这篇博客中,我们将手写一个HashSet类,实现HashSet的基本操作,包括添加元素、删除元素、查找元素等。

1. 创建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中的元素个数。

2. 实现散列函数

接下来,我们需要实现一个散列函数,将元素映射到数组的索引位置。

private int hash(E element) {
    return element.hashCode() % table.length;
}

在这个散列函数中,我们使用元素的hashCode方法来获取散列码,然后使用取余运算符将散列码映射到数组的索引位置。

3. 实现添加元素操作

接下来,我们将实现向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的元素个数。

4. 实现删除元素操作

接下来,我们将实现从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的元素个数。

5. 实现查找元素操作

接下来,我们将实现从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。

6. 实现Entry类

为了存储元素和构建链表,我们需要实现一个名为Entry的内部类。

private static class Entry<E> {
    E element;
    Entry<E> next;

    public Entry(E element) {
        this.element = element;
        this.next = null;
    }
}

Entry类包含一个元素和一个指向下一个节点的引用。

7. 总结

通过以上步骤,我们成功实现了一个简单的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来存储数据,我们可以快速地进行查找和判断操作,从而实现高效的数据过滤功能。

你可能感兴趣的:(Java手写源码合集,哈希算法,散列表,数据结构)