模拟HashSet底层实现

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: []
 * */






猜你喜欢

转载自blog.csdn.net/ldw201510803006/article/details/80726905