手写HashMap

jdk1.7的HashMap的底层实现主要是基于数组和链表来实现的,HashMap中通过key的hashCode来计算hash值的,再由这个hash值计算其在数组中的位置,将新插入的元素放到数组的这个位置,如果新插入的元素的hash值跟这个位置上已有元素的hash值相同,就会出现hash冲突,这时候,就在该位置通过链表来插入新的元素。
如下图:
在这里插入图片描述
具体代码如下:
Map接口:

public interface Map {
	int size();
	boolean isEmpty();
	Object get(Object key);
	Object put(Object key, Object value);
	interface Entry{
		Object getKey();
		Object getValue();
	}
}

HashMap的实现:

package com.dalingjia.collection.myHashMap;

/**
 * 数组加链表的结构 jdk1.7
 */
public class HashMap implements Map {

	//默认容量16
	private final int DEFAULT_CAPACITY = 16;

	//扩容因子0.75
	static final float DEFAULT_LOAD_FACTOR = 0.75f;

	//内部存储结构,数组
	Node[] table = new Node[DEFAULT_CAPACITY];

	//集合中元素实际个数
	private int size = 0;
	
	@Override
	public int size() {
		return size;
	}

	@Override
	public boolean isEmpty() {
		return size == 0;
	}

	/**
	 * 取值
	 */
	@Override
	public Object get(Object key) {
		//获取key的hash值
		int hashValue = hash(key);
		//求key所在数组的位置
		int index = indexFor(hashValue, table.length);
		for (Node node = table[index]; node != null ; node = node.next) {
			//hash值相同,key也相同,则返回该节点的value
			if (node.hash == hashValue && node.key.equals(key)) {
				return node.value;
			}
		}
		return null;
	}

	/**
	 * 存值
	 * 关于返回值:如果当前有一个相同的key,那么返回值是之前key对应的value,即oldValue
	 * 			如果是新的key,则返回null
	 * hashset中的add方法调用的是hashmap的put方法,通过判断put方法的返回值是否为空,
	 * 来保证hashset的值不重复
	 */
	@Override
	public Object put(Object key, Object value) {
		//获取key的hash值
		int hashValue = hash(key);
		//求key所在数组的位置
		int index = indexFor(hashValue, table.length);
		//index位置已经有数据了
		for(Node node = table[index]; node != null ; node = node.next){
			//链表中已有该key,则替换对应的value值,并将旧的oldValue返回
			if (node.hash == hashValue && node.key.equals(key)) {
				Object oldVaue = node.value;
				node.value = value;
				return oldVaue;
			}
		}
		/**
		 * 如果index位置没有数据,或是index位置有数据,但是不存在相同的key,则需要新增node
		 */
		addEntry(hashValue, key, value, index);
		//如果是新的key,则返回null
		return null;
	}

	public void addEntry(int hash, Object key, Object value, int i){
		//集合中元素增加时,需要判断集合是否需要扩容
		if(size >= table.length * DEFAULT_LOAD_FACTOR && (null != table[i])){
			//扩容
			resize(2 * table.length);
			hash = (null != key) ? hash(key) : 0;
			i = indexFor(hash, table.length);
		}
		//插入新元素
		createEntry(hash, key, value, i);
	}

	void createEntry(int hash, Object key, Object value, int i) {
		/*
		 * 当i位置为null时,将null作为新增node的下一个节点,新增node放在table[i]处,这样是没问题的
		 * 当i位置不为null时,将新增节点放在原始节点的前面,所以新增node的next指向原始i位置的node
		 * 所以2者结合起来,使用同一行代码
		 */
		Node node = table[i];//获取当前位置的node
		//生成一个新的node,并放到数组的index
		table[i] = new Node(hash, key, value, node);
		size++;
	}

	/**
	 * 扩容
	 * @param newCapacity
	 */
	private void resize(int newCapacity) {
		Node[] newTable = new Node[newCapacity];
		transfer(newTable, true);
		table = newTable;
	}

	/**
	 * rehash元素到新的数组中
	 * @param newTable
	 * @param b
	 */
	private void transfer(Node[] newTable, boolean b) {
		int newCapacity = newTable.length;
		for (Node e: table) {
			while (e != null) {
				Node next = e.next;
				int i = indexFor(e.hash, newCapacity);
				e.next = newTable[i];
				newTable[i] = e;
				e = next;
			}
		}
	}

	public int hash(Object key){
//		return key.hashCode();
		int h;
		return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
	}

	public int indexFor(int hashValue, int length){
		return hashValue & (length - 1);
	}


}

Node结点:

/**
 * 数组中的元素结点
 * @author tanhq
 *
 */
public class Node implements Map.Entry{
	int hash;
	Object key;
	Object value;
	Node next;//下一个结点
	public Node(int hash, Object key, Object value, Node next) {
		super();
		this.hash = hash;
		this.key = key;
		this.value = value;
		this.next = next;
	}

	@Override
	public Object getKey() {
		return key;
	}

	@Override
	public Object getValue() {
		return value;
	}
}

测试类

public class TestMyHashMap {
	public static void main(String[] args) {
		//每个java类都需要至少有一个构造方法,所以对于代码里没有构造方法的,就自动生成一个无参的
		HashMap hashMap=new HashMap();
		hashMap.put("aaa", "1111");
		hashMap.put("bbb", "2222");
		hashMap.put("ccc", "3333");
		hashMap.put("ddd", "4444");
		hashMap.put("eee", "5555");
		hashMap.put("fff", "6666");
		hashMap.put("ddd", "7777");
		System.out.println(hashMap.get("ccc"));
		System.out.println(hashMap.get("ddd"));
	}
}
好的,这里是一个简单的手写hashmap的实现: ```java public class MyHashMap<K, V> { private int size; private int capacity; private Node<K, V>[] table; private static class Node<K, V> { final K key; V value; Node<K, V> next; Node(K key, V value, Node<K, V> next) { this.key = key; this.value = value; this.next = next; } } public MyHashMap(int capacity) { this.size = 0; this.capacity = capacity; this.table = new Node[capacity]; } public V get(K key) { int index = hash(key); Node<K, V> node = table[index]; while (node != null) { if (node.key.equals(key)) { return node.value; } node = node.next; } return null; } public void put(K key, V value) { int index = hash(key); Node<K, V> node = table[index]; while (node != null) { if (node.key.equals(key)) { node.value = value; return; } node = node.next; } // If the key does not exist in the map, add a new node to the front of the list at the index. Node<K, V> newNode = new Node<>(key, value, table[index]); table[index] = newNode; size++; // If the map has exceeded its load factor, resize the table. if (size > capacity * 0.75) { resize(); } } public void remove(K key) { int index = hash(key); Node<K, V> node = table[index]; Node<K, V> prev = null; while (node != null) { if (node.key.equals(key)) { if (prev == null) { table[index] = node.next; } else { prev.next = node.next; } size--; return; } prev = node; node = node.next; } } private int hash(K key) { return key.hashCode() % capacity; } private void resize() { capacity *= 2; Node<K, V>[] newTable = new Node[capacity]; for (Node<K, V> node : table) { while (node != null) { Node<K, V> next = node.next; int index = hash(node.key); node.next = newTable[index]; newTable[index] = node; node = next; } } table = newTable; } } ``` 这个HashMap使用链表来解决冲突,并且在size超过capacity*0.75时会自动扩容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值