HashMap principle and simple implementation

public class MyHashMap<K, V> {
	private class Entry<K, V> {
		int hash;
		K key;
		V value;
		Entry<K, V> next;

		Entry(int hash, K key, V value, Entry<K, V> next) {
			this.hash = hash;
			this.key = key;
			this.value = value;
			this.next = next;
		}
	}

	private static final int DEFAULT_CAPACITY = 1 << 2;

	private Entry<K, V>[] table;

	private int capacity;

	private int size;

	private final float loadFactor = 0.75f;

	public MyHashMap() {
		this(DEFAULT_CAPACITY);
	}

	@SuppressWarnings("unchecked")
	public MyHashMap(int capacity) {
		if (capacity < 0) {
			throw new IllegalArgumentException();
		} else {
			table = new Entry[capacity];
			size = 0;
			this.capacity = capacity;
		}
	}

	public int size() {
		return size;
	}

	public boolean isEmpty() {
		return size == 0 ? true : false;
	}

	public V put(K key, V value) {
		if (key == null) {
			throw new RuntimeException("key cannot be empty!");
		}
		if (size >= capacity * loadFactor) {
			// start rehash
			resize(2 * table.length);
			int hash = (null != key) ? hash(key) : 0;
			int index = indexFor(hash, table.length);// Note that the table has been expanded at this time
		}
		V newValue = putEntry(key, value);
		return newValue;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void resize(int newCapacity) {
		System.out.println("We are going to expand!! The current size is: " + size);
		// multiply the length of the array by twice
		Entry[] newTable = new Entry[newCapacity];
		transfer(newTable, true);
		table = newTable;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void transfer(Entry[] newTable, boolean rehash) {
		int newCapacity = newTable.length;
		for (Entry<K, V> e : table) {
			while (e != null) {
				if (rehash) {
					// to re-hash
					e.hash = null == e.key ? 0 : hash(e.key);
				}
				int index = indexFor(e.hash, newCapacity);
				// start putting e into the new array
				// Note that every time a new value is inserted, it must be inserted at the head of the hash list
				e.next = newTable[index];
				newTable[index] = e;
				e = e.next;
			}
		}
	}

	private V putEntry(K key, V value) {
		if (key == null) {
			throw new RuntimeException("key cannot be empty!");
		}
		int hash = hash(key);
		int i = indexFor(hash, table.length);
		Entry<K, V> newEn = new Entry<K, V>(hash, key, value, null);
		for (Entry<K, V> e = table[i]; e != null; e = e.next) {
			Object k;
			if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
				// Represents that the current e conflicts with the key to be added, then overwrite
				V oldValue = e.value;
				e.value = value;// The current value of e should be replaced with the new value
				return oldValue;
			}
		}
		// If the above is not found, it is necessary to add an element to the linked list
		size++;
		addEntry(newEn, i);
		return value;
	}

	private void addEntry(Entry<K, V> entry, int index) {
		Entry<K, V> e = table[index];
		table[index] = entry;
		entry.next = e;
	}

	public V get(K key) {
		if (key == null) {
			throw new RuntimeException("key cannot be empty!");
		}
		Entry<K, V> entry = getEntry(key);
		return null == entry ? null : entry.value;
	}

	private Entry<K, V> getEntry(K key) {
		if (size == 0) {
			return null;
		}
		int hash = (key == null) ? 0 : hash(key);
		int i = indexFor(hash, table.length);
		for (Entry<K, V> e = table[i]; e != null; e = e.next) {
			Object k;
			if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
				return e;
			}
		}
		return null;
	}

	public V remove(K key) {
		Entry<K, V> e = removeEntryForKey(key);
		return (e == null ? null : e.value);
	}

	private Entry<K, V> removeEntryForKey(K key) {
		if (size == 0) {
			return null;
		}
		int hash = (key == null) ? 0 : hash(key);
		int i = indexFor(hash, table.length);
		Entry<K, V> cur = table[i];
		Entry<K, V> e = cur;
		while (e != null) {
			if (e.hash == hash && (e.key == key || key.equals(e.key))) {
				size--;
				// if the delete is prev
				if (cur == e) {
					table[i] = e.next;
				} else {
					// Let cur's next equal to e's next
					cur.next = e.next;
				}
				return e;
			}
			cur = e;
			e = e.next;
		}
		return null;
	}

	private int indexFor(int hash, int length) {
		return hash & (length - 1);// The hash value and the length minus one do the AND operation
	}

	private int hash(K key) {
		return key.hashCode();
	}

	public static void main(String[] args) {
		MyHashMap<Integer, String> map = new MyHashMap<>();
	}
}

  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324643469&siteId=291194637