📜  实现 LinkedHashSet API 的Java程序(1)

📅  最后修改于: 2023-12-03 15:25:09.553000             🧑  作者: Mango

实现 LinkedHashSet API 的 Java 程序

LinkedHashSet 是 Java 集合框架中的一个类,它继承自 HashSet,内部使用链表维护元素的顺序。相比于 HashSet,LinkedHashSet 能够保持元素的插入顺序,而且元素在遍历时会按照插入顺序进行。

这篇文章将介绍如何通过 Java 代码实现 LinkedHashSet 的主要 API,即 add、remove、contains 和 iterator。我们将从零开始,一步步地构建 LinkedHashSet 类。

概述

LinkedHashSet 的实现基于哈希表,使用桶(bucket)存储元素。每个桶包含一个链表,链表中的每个节点都包含一个元素和指向下一个节点的引用。

在插入元素时,我们需要先计算出元素的哈希值并对桶的数量取模,得到该元素所对应的桶的索引。然后,我们将元素插入到对应桶的链表的末尾。

在查找元素时,我们需要先计算出元素的哈希值并对桶的数量取模,得到该元素所对应的桶的索引。然后,我们遍历对应桶的链表,查找是否存在与该元素相同的元素。

在删除元素时,我们需要先计算出元素的哈希值并对桶的数量取模,得到该元素所对应的桶的索引。然后,我们遍历对应桶的链表,查找是否存在与该元素相同的元素。如果找到了,我们就删除该元素所在的节点。

在遍历元素时,我们需要依次访问每个桶,然后遍历每个桶中链表的每个节点,返回元素的顺序即可。

现在,我们来一步步实现 LinkedHashSet 的主要 API。

1. 定义 Node 类

在实现 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;
    }
}
2. 定义 LinkedHashSet 类

接下来,我们需要定义 LinkedHashSet 类。在这个类中,我们需要定义一个 Node 类型的数组 buckets,用于存储元素。我们还需要定义一个整型变量 size,表示集合中元素的数量。

public class LinkedHashSet<E> {
    private Node<E>[] buckets;
    private int size;
}
3. 构造函数和 add 方法

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;
    }
}
4. remove 和 contains 方法

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;
    }
}
5. iterator 方法

最后,我们需要实现 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;
        }
    };
}
6. 总结

我们已经实现了 LinkedHashSet 的主要 API,包括 add、remove、contains 和 iterator 方法。虽然这个过程比较繁琐,但是通过一步步实现,我们可以更好地理解 LinkedHashSet 的工作原理。

LinkedHashSet 是一个非常有用的集合类,它能够保持元素的插入顺序,并且在遍历时按照插入顺序进行。掌握 LinkedHashSet 的使用和实现可以帮助我们更好地理解 Java 集合框架。