GitHub源码地址(https://github.com/BradenLei/MyHashSet)
1、基本概念:
1)HashSet和HashMap唯一的不同之处在于,HashMap以键值对作为一个条目存储在散列表中,而HashSet则以元素的形式存储在散列表中;HashSet相当于HashMap的简化版。
2)MySet继承自java.lang.Iterable,实现了其方法,故MyHashSet中的元素是可以遍历的。
3)时间复杂度:clear()、iterator()、rehash()都是O(capacity),而contains() 、 add()、remove()、isEmpty()、size()都是O(1)。
具体实现:
MySet接口:
package hash;
public interface MySet<E> extends java.lang.Iterable<E> {
/**清除所有元素*/
public void clear();
/**Return true if the element is in the set*/
public boolean contains(E e);
/**add a element to the set*/
public boolean add(E e);
/**Remove the element from the set*/
public boolean remove(E e);
/**set是否为空*/
public boolean isEmpty();
/**返回set大小*/
public int size();
}
实现:
package hash;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
public class MyHashSet<E> implements MySet<E>{
/**初始哈希表大小,必须是2的幂次方*/
private static int DEFAULT_INITIAL_CAPACITY = 4;
/**默认最大哈希表容量,2^30*/
private static int MAXIMUM_CAPACITY = 1 << 30;
/**哈希表容量*/
private int capacity;
/**默认装载因子*/
private static float DEFAULT_MAX_LOAD_FACTOR = 0.75f;
/**指出特定的装载因子*/
private float loadFactorThreshold;
/**entry数量*/
private int size = 0;
/**hash table*/
private LinkedList<E>[] table;
/**使用默认容量和装载因子的构造函数*/
public MyHashSet() {
this(DEFAULT_INITIAL_CAPACITY,DEFAULT_MAX_LOAD_FACTOR);
}
/**指定初始容量*/
public MyHashSet(int initialCapacity) {
this(initialCapacity,DEFAULT_MAX_LOAD_FACTOR);
}
/**指定初始容量及装载因子*/
public MyHashSet(int initialCapacity,float loadFactorThreshold) {
if(initialCapacity > MAXIMUM_CAPACITY)
this.capacity = MAXIMUM_CAPACITY;
else
this.capacity = trimToPowerOf2(initialCapacity);
this.loadFactorThreshold = loadFactorThreshold;
table = new LinkedList[capacity];
}
/**Return a power of 2 for initialCapacity*/
private int trimToPowerOf2(int initialCapacity) {
int capacity = 1;
while(capacity < initialCapacity) {
capacity <<= 1;
}
return capacity;
}
/**cleart the set*/
@Override
public void clear() {
size = 0;
removeElements();
}
private void removeElements() {
for(int i = 0; i < capacity; i++) {
if(table[i] != null) {
table[i].clear();
}
}
}
/**是否包含指定元素*/
@Override
public boolean contains(E e) {
int bucketIndex = hash(e.hashCode());
if(table[bucketIndex] != null) {
LinkedList<E> bucket = table[bucketIndex];
for(E element : bucket) {
if(element.equals(e)) {
return true;
}
}
}
return false;
}
/**hash fucntion*/
private int hash(int hashCode) {
return supplementalHash(hashCode) & (capacity - 1);
}
/**确保hash值均匀分布*/
private int supplementalHash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
/**add a element to the set*/
@Override
public boolean add(E e) {
if(contains(e))
return false;
if(size + 1 > capacity * loadFactorThreshold) {
if(capacity == MAXIMUM_CAPACITY)
throw new RuntimeException("Exceeding maximum capacity");
rehash();
}
int bucketIndex = hash(e.hashCode());
//Create a linked list for the bucket if not already created
if(table[bucketIndex] == null) {
table[bucketIndex] = new LinkedList<>();
}
table[bucketIndex].add(e);
size++;
return true;
}
/**再散列*/
private void rehash() {
ArrayList<E> list = setToList();
capacity <<= 1;
table = new LinkedList[capacity];
size = 0;
for (E e : list) {
add(e);
}
}
/**Copy elements in the hash set to an array list*/
private ArrayList<E> setToList() {
ArrayList<E> list = new ArrayList<>();
for(int i = 0; i < capacity; i++) {
if(table[i] != null) {
for (E e : table[i]) {
list.add(e);
}
}
}
return list;
}
/**Remove the element from the set*/
@Override
public boolean remove(E e) {
if(!contains(e))
return false;
int bucketIndex = hash(e.hashCode());
//Remove the element from the bucket
if(table[bucketIndex] != null) {
LinkedList<E> bucket = table[bucketIndex];
for (E element : bucket) {
bucket.remove(element);
break;
}
}
size--;
return true;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public int size() {
return size;
}
@Override
public Iterator<E> iterator() {
return new MyHashSetIterator(this);
}
/**Inner class for iterator*/
private class MyHashSetIterator implements java.util.Iterator<E>{
private ArrayList<E> list;
private int current = 0;
private MyHashSet<E> set;
public MyHashSetIterator(MyHashSet<E> set) {
this.set = set;
list = setToList();
}
@Override
public boolean hasNext() {
if(current < list.size())
return true;
return false;
}
@Override
public E next() {
return list.get(current++);
}
@Override
public void remove() {
set.remove(list.get(current));
list.remove(current);
}
}
@Override
public String toString() {
ArrayList<E> list = setToList();
StringBuilder builder = new StringBuilder("[");
for(int i = 0; i < list.size() - 1; i++) {
builder.append(list.get(i) + ", ");
}
if(list.size() == 0)
builder.append("]");
else {
builder.append(list.get(list.size() - 1) + "]");
}
return builder.toString();
}
}
测试:
package hash;
public class TestMyHashSet {
public static void main(String[] args) {
MySet<String> set = new MyHashSet<>();
set.add("Smith");
set.add("Anderson");
set.add("Lewis");
set.add("Cook");
set.add("Smith");
System.out.println("Element in set: " + set);
System.out.println("Number of elements in set: " + set.size());
System.out.println("Is Smith in set? " + set.contains("Smith"));
set.remove("Smith");
System.out.print("Names in set in uppercase are ");
for (String s : set) {
System.out.print(s.toUpperCase() + " ");
}
set.clear();
System.out.println("\nElement in set: " + set);
}
}
/**
Element in set: [Anderson, Smith, Lewis, Cook]
Number of elements in set: 4
Is Smith in set? true
Names in set in uppercase are ANDERSON LEWIS COOK
Element in set: []
* */