IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 哈希表由浅入深 -> 正文阅读

[数据结构与算法]哈希表由浅入深

哈希表由浅入深🔥

一、前置理解

哈希表

哈希表(也叫散列表),是根据键(Key)而直接访问在内存存储位置的数据结构。
哈希表底层就是数组。

hashCode

hashCode 称为 哈希码 也叫 散列码。是一个 int 值, 用来表示一个对象。
默认是通过地址转换的,一般重写让它是通过将该对象的某些信息进行转换而生成的。
hashCode方法 主要是为了给诸如HashMap这样的哈希表使用

哈希算法

简单的理解就是把 hashcode 转成下标的规则方式。

二、哈希表案例

举例: 我存储了一个学校的学生对象。现在有个需求, 我要查找姓名叫张三的学生。

数组解决

使用数组存储学生,然后从第一个元素遍历。 判断每一个学生的名字等不等于张三。
弊端 如果学生比较多。每次查询需要从第一个元素遍历,直到找到元素,效率太低了

哈希表解决

添加元素的时候,每个对象的 hashcode 通过算法转成下标。该学生对象保存在该下标。
我要找张三的话, 不管多少元素,直接把张三的 hashcode 转成下标, 通过下标一次查找就找到该元素了。

比如现在我使用的算法就是 (hashcode 对 数组长度取模),为了容易理解, 真正的算法肯定不是这样的。

在这里插入图片描述
弊端 可能会出现哈希冲突。

三、什么是哈希冲突

哈希冲突就是两个不同的元素,通过哈希函数得出的实际存储地址相同了。也叫哈希碰撞。

举个例子

数组长度是 10,张三对象的 hashcode 通过算法得到下标为 3, 李四对象的 hashcode 通过算法得到下标也是 3,这就是哈希冲突。

在这里插入图片描述

疑问:好的算法会哈希冲突吗

由于通过哈希函数产生的哈希值是有限的,拿 Java举例 hashcode的取值范围为 -2^31 到 2^31-1
而数据(对象)理论上是无穷的。
稍微思考一下就可以发现,既然数据是不定长的,但是哈希值是定长的,哈希值是有限集,而数据可以是无限多的。
所以“碰撞”是必然会发生的,一个成熟的哈希算法会有更好的防碰撞性。 但是还是会出现哈希冲突

四、解决哈希冲突

JDK1.7 实现方式

哈希冲突的解决方案有很多种,这里讲其中一种:链地址法
JDK 1.7 即之前版本 HashMap 使用的就是这种方式

在这里插入图片描述
当出现冲突时,在冲突的地址上生成一个链表,将冲突的元素的 key,通过equals进行比较。
这时候就算张三和李四冲突了。equals 比较他们不是同一个人,李四放在链表的第二个位置即可。是同一个人就不会添加重复元素张三了。
查找张三和李四的时候 还是通过 哈希算法 得到索引,再拿索引中链表的元素一个一个比较, 效率仍然很高

JDK1.8 实现方式

JDK1.7 中,如果链表过长的话,查询效率会降低,
JDK1.8 之后,又添加了红黑树,如果链表过长了会自动把该链表转成红黑树,从而提高效率

在这里插入图片描述

五、为什么必须重写 hashcode 和 equals

为什么重写 hashcode

hashcode 方式是Object 中的本地方法,返回的是对象地址转成的 int 值。
因为要保证相同的对象hashcode相同,所以需要重写。

1. 未重写hashcode

未重写hashcode

    public static void main(String[] args) {
        Student student = new Student("小明", 18);
        Student student2 = new Student("小红", 20);
        Student student3 = new Student("小红", 20);
        System.out.println(student.hashCode());
        System.out.println(student2.hashCode());
        System.out.println(student3.hashCode());
    }
1735600054
21685669
2133927002

在我们看来 student2student3 是同一个元素, 但是 hashcode 值却不同。
问题:
这样的话,使用 hashMap 保存数据就会导致添加的数据在数组中重复,因为他是通过 hashcode 确定索引位置的。

2. 重写hashcode

因为要保证相同的对象 hashcode 相同,所以必须要重写。
可以使用 IDEA 快速重写,大概重写规则就是和属性关联,属性相同的对象,hashcode相同。

	public static void main(String[] args) {
        Student student = new Student("小明", 18);
        Student student2 = new Student("小红", 20);
        Student student3 = new Student("小红", 20);
        System.out.println(student.hashCode());
        System.out.println(student2.hashCode());
        System.out.println(student3.hashCode());
    }
23458772
23653826
23653826

为什么重写equals

因为需要使用 equals 判断对象是否相等,避免一个链表上重复添加相同对象。

结论

重写 hashcode 保证数组中相同元素不重复
重写 equals 保证链表中相同元素不重复

  • equals相等,hashCode一定相等
  • equals不等,hashcode不一定不等
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-09-25 23:20:35  更:2022-09-25 23:21:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 17:28:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码