Java 中的HashMap(默认大小、扩容机制、哈希算法)

本文详细介绍了Java中的HashMap,包括其内部的哈希表结构、默认容量、负载因子以及扩容机制。当负载因子达到0.75时触发扩容,容量翻倍。此外,HashMap使用链地址法解决哈希冲突,当链表长度超过8时转为红黑树,长度小于6时再转回链表。哈希算法确保高效查找,而自定义的哈希表实现展示了基本的键值对存储和查找操作。
摘要由CSDN通过智能技术生成

Java 中的HashMap

哈希表是一个散列表,存储着Key-Value键值对,插入和查找的复杂度均为O(1)。
java中在创建哈希表时会创建一个默认大小的数组。插入一个键值对时,利用一个哈希算法确定key存储在数组的哪个位置,这时可能会出现哈希冲突问题,即不同key生成同样的hashcode。
此时利用链地址法,将每个位置创建一个链表来解决该问题,可将键值对插入到链表尾部,当链表长度大于8时转化为红黑树,当长度小与6时会将红黑树转化为链表。
在java中当实际负载因子大于默认的负载因子(0.75)时会触发扩容机制,每次扩容时容量变为原来大小的两倍

默认大小

默认的哈希表容量为16,当负载因子达到0.75时,某个链表长度为8的概率是非常小的。

哈希表的扩容机制

负载因子 = 存储的键值对元素个数/哈希表的容量
在java中当实际负载因子大于默认的负载因子(0.75)时会触发扩容机制,每次扩容时容量变为原来大小的两倍
当链表长度大于8时转化为红黑树,当长度小与6时会将红黑树转化为链表。因为链表的查询复杂度为O(n)而红黑树的查询复杂度为O(logn),在n较小时差距不大,当n变多后则红黑树的优势就体现了出来。一般来说hash算法使某个链表节点数变为8的概率非常之小,主要是为了防止使用了不合适的hash算法。

哈希算法

hash算法能将任意长度的二进制明文映射为较短的二进制串,并且不同的明文很难映射为相同的hash值
输入的数据可以有无穷个,而哈希值的取值范围有限,所以可能会出现哈希冲突,好的哈希算法会有效避免这种冲突
具有如下几个特点
1、正向快速
可以在有限时间资源内计算得到hash值
2、逆向困难
给定hash值,很难倒推明文
3、输入敏感
输入信息发生任何变化都会导致hash值出现很大变化
4、冲突避免
很难找到不同明文的hash值相同的情况

简单实现哈希表
public class HashMapTest {
	//保存链表的数组
	public Linked[] linkArr;
	public static final int LEN = 16;
	
	public HashMapTest(int len) {
		//初始长度
		linkArr = new Linked[len];
	}
	//默认长度
	public HashMapTest() {
		this(LEN);
	}
	//put数据
	public void put(Object key,Object value) {
		//根据key 值,计算数组(保存位置)
		if(key == null) {
			if(linkArr[0] == null) {
				linkArr[0] = new Linked();
			}
			linkArr[0].add(key, value);
			return;
		}
		int index = hash(key);
		if(linkArr[index] == null) {
			linkArr[index] = new Linked();
		}
		//找到该key对应的链表,添加到末尾
		linkArr[index].add(key, value);

	}
	//get数据
	public Object get(Object key){
		int index;
		//找到给key
		if(key ==null) {
			index = 0;
		}else {
			index = hash(key);
		}
		
		return linkArr[index].get(key);
	}
	
	//哈希算法
	//系统中的哈希算法?
	public int hash(Object key) {
		return Math.abs(key.hashCode())%LEN;
	}
	
	public static void main(String[] args) {
		HashMapTest test = new HashMapTest(16);
		test.put("hisahd", 885);
		test.put("hisahd", 777);
		test.put(null, null);
		System.out.println(test.get(null));
		System.out.println(test.get("hisahd"));
	}

}

自定义的链表类

public class Linked {
	public Node root;
	public Node last; 
	public int size = 0;
	
	//初始化根节点
	public Linked() {
		root = new Node();
	}
	
	//添加节点到末尾
	public void add(Object key,Object value) {
		if(this.contain(key)==true) {
			this.reset(key, value);
			return;
		}
		Node point = new Node(key,value);
		Node head = root.next;
		if(head == null) {
			root.next = point;
			root.next.key = key;
			root.next.value = value;
			last = head;
			
		}else {
			last.next = point;
			last = point;
			last.key = key;
			last.value = value;
		}
		++size;
	}
	public Object get(Object key) {
		Node head = root.next;
		if(key == null) {
			for(int i = 0; i < size; ++i) {
				if(head.key == null) {
					return head.value;
				}
				head = head.next;
			}
		}else {
			for(int i = 0; i < size; ++i) {
				if(head.key.equals(key)) {
					return head.value;
				}
				head = head.next;
			}
		}
		return "不存在";
		
	}
	public boolean contain(Object key) {
		Node head = root.next;
		if(key == null) {
			for(int i = 0; i < size; ++i) {
				if(head.key == null) {
					return true;
				}
				head = head.next;
			}
		}else {
			for(int i = 0; i < size; ++i) {
				if(head.key.equals(key)) {
					return true;
				}
				head = head.next;
			}
		}
		return false;
		
	}
	public void reset(Object key, Object value) {
		Node head = root.next;
		if(key == null) {
			for(int i = 0; i < size; ++i) {
				if(head.key == null) {
					head.value = value;
				}
				head = head.next;
			}
		}else {
			for(int i = 0; i < size; ++i) {
				if(head.key.equals(key)) {
					head.value = value;
				}
				head = head.next;
			}
		}
	}
}
//节点类
class Node{
	public Object key;
	public Object value;
	public Node next;
	
	public Node() {
		
	}
	public Node(Object key,Object value) {
		this.key = key;
		this.value = value;
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值