三木之纯手写HashMap

HashMap(基于JDK1.8版本实现)

底层实现方式:JDK1.8的hashmap  数组+链表+红黑树

当冲突同一index个数大于8时,才会使用红黑树

 

 

HashMap(基于JDK1.7版本实现)

注意,存在死循环情况:
jdk1.7 多线程情况下扩容会产生闭环,取数据的时候就会进行死循环,因为get 是for遍历 用的是e.next 会导致死循环

链接:HashMap的死循环【基于JDK1.7】

 

底层实现方式:JDK1.7的hashmap  数组+链表(单链表)

1.创建Map接口

public interface ExtMap<K, V> {

	// 向集合中插入数据
	public V put(K k, V v);

	// 根据k 从Map集合中查询元素
	public V get(K k);

	// 获取集合元素个数
	public int size();

	interface Entry<K, V> {
		K getKey();

		V getValue();

		V setValue(V value);
	}

}

2.创建HashMap实现

public class MyHashMap<K,V> implements ExtMap<K, V>  {
	
	// 1.定义table 存放HasMap 数组元素 默认是没有初始化容器 懒加载
	Node<K, V>[] table = null;
	// 2. 实际用到table 存储容量 大小
	int size;
	// 3.HashMap默认负载因子,负载因子越小,hash冲突机率越低, 根据每个链表的个数
	float DEFAULT_LOAD_FACTOR = 0.75f;
	// 4.table默认初始大小 1
	static int DEFAULT_INITIAL_CAPACITY = 1<<4; // 1<<4二进制移位,效率高      1<<4其实就是16

	@Override
	public V put(K key, V value) {
		
		//1.判断 table是否为空
		if(table==null){
			table=new Node[DEFAULT_INITIAL_CAPACITY];
		}
		
		/* 2.判断size是否大于DEFAULT_INITIAL_CAPACITY*DEFAULT_LOAD_FACTOR
		 * 如果大于等于,进行扩容
		 */
		if(size>=(DEFAULT_INITIAL_CAPACITY*DEFAULT_LOAD_FACTOR)){
			//进行扩容
			resize();
		}
		
		//3.计算哈希值hash   取模得到下标值
		int index = getIndex(key, DEFAULT_INITIAL_CAPACITY);
		
		/*4.若该下标位置 为空  ,则该节点存放到数组table的index下标位置
		 *	若不为空,查看该节点的key是否等于key 
		 *		若不相等,继续查下下个节点
		 *		若相等,更换值,并返回旧的值
		 */
		Node<K, V> node = table[index];
		if(node==null){
			node=new Node<K,V>(key, value, null);
			size++;
		}else {
			
			//取多一个值节点
			Node<K, V> newNode = node;
			while(newNode!=null){
				
				//若存在该值,覆盖旧的值,并返回 旧的值
				if(newNode.getKey().equals(key)||newNode.getKey()==key){
					return newNode.setValue(value);
				}else {
					
					//若该到了链表最后的节点为空,则将新的节点添加到链表的头部
					if(newNode.next==null){
						node=new Node<K,V>(key, value, node);
						size++;
					}
				}
				newNode=newNode.next;
			}
		}
		//将该节点存放到index下标位置
		table[index]=node;
		return null;
	}
	
	//hashmap数组扩容
	private void resize() {
		Node<K, V>[] newtable = new Node[DEFAULT_INITIAL_CAPACITY << 1];
		for(int i = 0;i<table.length;i++){
			Node<K, V> oldNode = table[i];
			while(oldNode!=null){
				
				//1.重新计算index 获取扩容后的下标值
				int index = getIndex(oldNode.getKey(), newtable.length);
				
				//2.保存 下个节点 
				Node oldnext=oldNode.next;
				
				//3.newtable[index]==>链表 直接链接到oldNode的next
				oldNode.next=newtable[index];
				
				//4.将重新链接好的链表  覆盖到  数组index对应的位置
				newtable[index]=oldNode;
				
				//5.将之前2步骤保存的节点 作为下一个节点 继续执行
				oldNode=oldnext;
				
			}
			//每完成数组一个下表位置的链表,则清空,减少内存占用以及数据的多余
			table[i] = null;
		}
		
		//执行完后,将newtable覆盖到原table,减少内存的占用
		table=newtable;
		DEFAULT_INITIAL_CAPACITY = newtable.length;
		newtable = null;// 将 对象变为不可达对象  垃圾回收
	}

	@Override
	public V get(K k) {
		
		Node<K, V> node = getNode(table[getIndex(k, DEFAULT_INITIAL_CAPACITY)],k);
		return node == null ? null : node.getValue();
	}
	
	public Node<K, V> getNode(Node<K, V> node,K k){
		
		while(node!=null){
			if(node.getKey().equals(k)||node.getKey()==k){
				return node;
			}
			node=node.next;
		}
		return null;
		
	}

	@Override
	public int size() {
		return size;
	}
	
	//取下标值 
	public int getIndex(K k,int length){
		int index = k == null ? 0 : k.hashCode() % length;
		return index;
		
	}
	
	//定义节点
	class Node<K , V> implements Entry<K, V>{

		private K key;
		private V value;
		private Node<K,V> next;
		
		@Override
		public K getKey() {
			return this.key;
		}

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

		@Override
		public V setValue(V value) {
			//返回旧的值
			V oldValue=this.value;
			this.value=value;
			return oldValue;
		}

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

    
    // 测试方法.打印所有的链表元素
		void print() {

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

				}
				System.out.println();
			}

		}
	
	
}

测试代码

public class TestMyHashMap {
    public static void main(String[] args) {
		
		// 基于原则 :后进先出  
		MyHashMap myHashMap = new MyHashMap<String, String>();
		myHashMap.put("1号", "1号");// 0
		myHashMap.put("2号", "2号");// 1
		myHashMap.put("3号", "3号");// 2
		myHashMap.put("4号", "4号");// 3
		myHashMap.put("6号", "6号");// 4
		myHashMap.put("7号", "7号");//5
		myHashMap.put("14号", "14号");//6

		myHashMap.put("22号", "22号");//7
		myHashMap.put("26号", "26号");//8
		myHashMap.put("27号", "27号");//9
		myHashMap.put("28号", "28号");//10
		myHashMap.put("66号", "66");//11
		//myHashMap.put("30号", "30号");
		System.out.println("扩容前数据....");
		myHashMap.print();
        
        //当size大于大于等于 DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR  进行扩容
		System.out.println("扩容后数据....");
		myHashMap.put("31号", "31号");
		myHashMap.put("66号", "123466666");
		myHashMap.print();
		// 修改3号之后
		System.out.println(myHashMap.get("66号"));
		// System.out.println("扩容之前获取数据:" + myHashMap.get("1号"));
		// myHashMap.print();
		// System.out.println();
		// // myHashMap.put(14 + "号", 14 + "号");
		// // myHashMap.put(1 + "号", "4444号");
		// System.out.println("扩容之后获取数据:" + myHashMap.get("1号"));
		// myHashMap.print();
		
		
	}
}

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值