Java基础_模拟HashMap集合(基于数组和链表)

创建Map接口

package com.lic.hashMap;
public interface MyMap {	
	void put(K key,V value);	
	
	Object get(K key);
	
	void remove(K key);	
	
	int size();
}

创建Entry接口

package com.lic.hashMap;
public interface Entry {
	K getKey();
	
	V getValue();
	
	void setValue(V value);
	
}

创建Node实现类

package com.lic.hashMap;

public class Node implements Entry {

	private K key;
	private V value;

	private Node next;

	public Node getNext() {
		return next;
	}

	public void setNext(Node next) {
		this.next = next;
	}

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

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

	@Override
	public void setValue(V value) {
		this.value = value;
	}

	public Node(K key, V value, Node next) {
		super();
		this.key = key;
		this.value = value;
		this.next = next;
	}

}

创建HashMap实现类

package com.lic.hashMap;

public class MyHashMap implements MyMap {
	// 1.定义table 存放HasMap 数组元素 默认是没有初始化容器 懒加载
	private Node[] table = null;
	// 2. 实际用到table 存储容量 大小
	int size;
	// 3.HashMap默认负载因子,负载因子越小,hash冲突机率越低, 根据每个链表的个数
	float DEFAULT_LOAD_FACTOR = 0.75F;
	// 4.table默认初始大小 16
	static final int DEFAULT_INITIAL_CAPACITY = 16;

	@Override
	public void put(K key, V value) {
		if (table == null) {
			table = new Node[DEFAULT_INITIAL_CAPACITY];
		}
		// 如果存储数据数量 大于等于 负载因子与当前数组容器长度的乘积,则进行扩容
		if (size >= DEFAULT_LOAD_FACTOR * table.length) {
			reSize();
		}
		int hash = getHashCode(key, table.length);
		Node node = table[hash];
		if (node == null) {
			table[hash] = new Node(key, value, null);
			size++;
		} else {
			Node oldNode = node;
			// 循环遍历查询该链表中是否已存在相同key的节点,如果存在,则替换
			while (oldNode != null) {
				if (oldNode.getKey().equals(key)) {
					oldNode.setValue(value);
					return;
				}
				oldNode = oldNode.getNext();
			}
			// 如果循环结束还未检索到有相同key的节点,则在链表头部添加新的节点信息,并将新节点的next设置为原头部节点
			Node newNode = new Node<>(key, value, node);
			table[hash] = newNode;
			size++;
		}
	}

	private void reSize() {
		// 1.创建新的数组来存储节点信息,新数组大小为原来的两倍
		Node[] newTable = new Node[table.length << 1];
		// 2.将原数组中的数据进行迁移
		for (int i = 0; i < table.length; i++) {
			// 遍历每个链表中的节点,重新计算索引
			Node oldNode = table[i];
			table[i] = null;
			while (oldNode != null) {
				// 重新计算链表中每个节点的索引,并将其存放在扩容后数组中的位置上
				int index = getHashCode(oldNode.getKey(), newTable.length);
			    //在oldNode.setNext(newTable[hashCode]);中会改变oldNode的next节点,所以提前提取出来
				Node oldNext = oldNode.getNext();
				
				//将索引位置的node节点设置为oldNode节点的下一个节点,然后将oldNode节点赋给newTable[hashCode]
				oldNode.setNext(newTable[index]);
				newTable[index] = oldNode;
				
				//进行下一次循环
				oldNode = oldNext;

			}
		}
		// 将原来的table置为空,将扩容后的newTable赋给table;
		table = null;
		table = newTable;
	}

	private int getHashCode(K key, int length) {
		return key.hashCode() % length;
	}

	@Override
	public Object get(K key) {
		if (table == null) {
			return null;
		}
		Node node = getNode(key, table.length);
		return node == null ? null : node.getValue();
	}

	private Node getNode(K key, int length) {
		int hash = getHashCode(key, length);
		Node node = table[hash];
		while (node != null) {
			if (node.getKey().equals(key)) {
				return node;
			}
			node = node.getNext();
		}
		return null;
	}

	public void print() {
		for (int i = 0; i < table.length; i++) {
			Node node = table[i];
			System.out.print("下标位置:[" + i + "]");
			while (node != null) {
				System.out.print("[key=" + node.getKey() + ",value=" + node.getValue() + "]");
				node = node.getNext();
			}

			System.out.println();
		}
	}

	@Override
	public void remove(K key) {
		int hash = getHashCode(key, table.length);
		Node node = table[hash];
		Node preNode = null;
		while (node != null) {
			if (node.getKey().equals(key)) {
				if (preNode != null) {
					preNode.setNext(node.getNext());
				} else {
					if (node.getNext() == null) {
						table[hash] = null;
					} else {
						table[hash] = node.getNext();
					}
				}
				node = null;
				return;
			}
			preNode = node;
			node = node.getNext();
		}
		return;
	}

	@Override
	public int size() {
		return size;
	}

}

你可能感兴趣的:(Java基础)