【数据结构 | 哈希表】一文了解哈希表(散列表)

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍哈希表 🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你------泰戈尔🍭
⏰发布时间⏰: 2024-07-24 14:48:55

本文未经允许,不得转发!!!

目录


🎄一、概述

在学习过的简单数据结构当中,

数组的特点:访问(寻址)速度较快的 、但插入、删除操作较慢;

链表的特点:访问(寻址)速度较慢的、但插入、删除操作很快

所以,有些大牛就想着能不能结合这数组、链表的优点,造出一个 访问(寻址)速度较快的、插入、删除操作也很快 的数据结构,后面就造出来一个 哈希表。

哈希表(Hash Table):也叫做散列表。是根据关键码值(Key Value)直接进行访问的数据结构。

哈希表存储的都是键值对(Key-Value),即一个关键字对应一个内容,给出关键字就可以在哈希表中找到对应内容。

哈希表的工作过程:哈希表通过键值对的 关键字(key)哈希函数 计算出对应的一个位置,通常是数组下标 ,然后把整个 键值对 (代码中叫Entry)存放到这个位置,以加快查找的速度。如果多个 关键字(key) 得到同一位置就会产生 哈希冲突,需要通过一个方法去解决。

这里面有好几个概念,会在后面的内容去介绍。


🎄二、键值对(key-value pair)

键值对(key-value pair) :就是一个关键字(key)对应一个值(value)的组合,要求每个键值对的 关键字(key) 不能重复。下面表格就是一些键值对。

Key Value
xia
za
zai
zan
zang

在代码里可以使用下面结构体去表现一个键值对:

cpp 复制代码
struct table_entry{
	const char* key;
	void *value;
}

哈希表是存储 键值对 的,那它是怎样存储的呢?

哈希表要求每个键值对的 关键字(key) 不能重复,然后通过键值对的 关键字(key) 来定位每个键值对存放的位置,这个位置就是 哈希地址 ,而将 关键字(key) 映射成 哈希地址 的函数就是 哈希函数

在哈希表中,会把 键值对(key-value) 的key称为键值。


🎄三、哈希函数

哈希函数(Hash Function):也叫散列函数,将哈希表中元素的关键键值(key)映射为元素存储位置(哈希地址)的函数。

哈希函数是哈希表中最重要的部分。一般来说,哈希函数会满足以下几个条件:

  • 哈希函数应该易于计算,并且尽量使计算出来的索引值均匀分布。

  • 哈希函数计算得到的哈希值是一个固定长度的输出值。

  • 计算出来的哈希地址不同,则传入键值(key)肯定不同;

    Hash(key1) != Hash(key2),则 key1 != key2。
    
  • 如果 Hash(key1) 等于 Hash(key2),那么 key1、key2 可能相等,也可能不相等(会发生哈希冲突)

在哈希表的应用中,最常见的2种键值类型是:字符串、数字。而其他键值类型还可以是是字符串类型、浮点数类型、大整数类型,甚至还有可能是几种类型的组合。设计哈希函数时,要根据键值类型的特点去设计,一般会先将键值转成整型再去计算,因为最终计算出来的一般是一个数组下标(Index)。

常见的哈希函数方法有:直接定址法、除留余数法、平方取中法、基数转换法、数字分析法、折叠法、随机数法、乘积法、点积法等。

假设我们把上个小节的键值对存到一个哈希表,并通过哈希函数计算出哈希地址,如下表:

Key Value 哈希地址(Index)
xia 517
za 597
zai 597
zan 599
zang 600

就像上面表格一样,哈希函数有时就将两个不同的键值计算出同一个哈希地址,这就造成了哈希冲突(哈希碰撞)


🎄四、哈希冲突(哈希碰撞)

哈希冲突(Hash Collision):不同的关键字通过同一个哈希函数可能得到同一哈希地址,即 key1 ≠ key2,而 Hash(key1) = Hash(key2),这种现象称为哈希冲突。

理想状态下,是每个key通过哈希函数都计算出不同的哈希地址,这样直接将键值对存入即可。但实际使用中一般都会出现哈希冲突的,这时就需要处理哈希冲突。处理哈希冲突的方法一般有两种:开放地址法、链地址法。

✨4.1 开发地址法

开放地址法(Open Addressing):指的是将哈希表中的 空地址 向处理冲突开放。当哈希表未满时,处理冲突时需要尝试另外的单元,直到找到空的单元为止。

开放地址法主要有三种实现:

  • 线性探测(Linear Probing):发生冲突时,依次检查下一个地址,直到找到空闲位置。
  • 二次探测(Quadratic Probing):冲突时,以二次函数的方式探查空闲位置。
  • 双重哈希(Double Hashing):使用两个哈希函数,当发生冲突时,使用第二个哈希函数计算新的探查位置。

✨4.2 链地址法

链地址法(Chaining):将具有相同哈希地址的元素(或记录)存储在同一个线性链表中。

链地址法是一种更加常用的哈希冲突解决方法。相比于开放地址法,链地址法更加简单。

具体的做法是当哈希地址的位置是空的话,就直接将 键值对 存入该位置;如果不为空,就将 键值对 存到该地址的链表中,所以在代码实现时,会在键值对所在结构体中加一个next指针,用于实现链表。

cpp 复制代码
struct TableEntry {
    TableEntry* fNext;
    char const* key;
    void* value;
};

🎄五、哈希表的使用

虽然上面说了那么多的概念,但只是使用哈希表并不需要知道这些。如果是要看别人实现哈希表的代码,则必须要清楚上面的那些概念,这里再总结一下:

  • 1、键值对(Key-Value Pair):是一种数据结构的表示形式,其中"键(Key)"是用于标识和查找数据的唯一标识符,"值(Value)"则是与该键相关联的数据。例如,在字典中,单词(键)与其释义(值)就构成了键值对。
  • 2、哈希函数(Hash Function):是一种将输入(通常是键)转换为固定长度输出(称为哈希值)的函数。哈希函数的设计目标是使得不同的输入尽可能产生不同的输出,并且输出分布均匀。
  • 3、哈希值(Hash Value):通过哈希函数对输入(键)进行计算得到的固定长度的数值。
  • 4、哈希地址(Hash Address):哈希值所对应的存储位置。通常,哈希表会根据哈希值来确定数据在内存中的存储位置。
  • 5、哈希冲突(Hash Collision):当两个或多个不同的键通过哈希函数计算得到相同的哈希值时,就发生了哈希冲突。这可能导致这些键对应的元素需要存储在同一个哈希地址,从而引发数据存储和检索的问题。

如果只是使用哈希表的话,只需要知道哈希表提供了哪些操作即可。哈希表至少会提供三个操作:插入、删除、查询。我们只需要知道怎样插入键值对、怎样删除、怎样查询就差不多了。


🎄六、总结

👉本文介绍哈希表实现过程中的重要概念:键值对、键值、哈希函数、哈希冲突、处理哈希冲突等,看完后可以对哈希表有一定的了解。

如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

参考:

https://blog.csdn.net/zy_dreamer/article/details/131036258

https://blog.csdn.net/sinat_33921105/article/details/103344078

https://blog.csdn.net/m0_65781965/article/details/136987203

相关推荐
Aileen_0v05 小时前
【AI驱动的数据结构:包装类的艺术与科学】
linux·数据结构·人工智能·笔记·网络协议·tcp/ip·whisper
是小胡嘛5 小时前
数据结构之旅:红黑树如何驱动 Set 和 Map
数据结构·算法
yuanManGan7 小时前
数据结构漫游记:静态链表的实现(CPP)
数据结构·链表
2401_8582861110 小时前
115.【C语言】数据结构之排序(希尔排序)
c语言·开发语言·数据结构·算法·排序算法
猫猫的小茶馆11 小时前
【数据结构】数据结构整体大纲
linux·数据结构·算法·ubuntu·嵌入式软件
2401_8582861112 小时前
109.【C语言】数据结构之求二叉树的高度
c语言·开发语言·数据结构·算法
huapiaoy12 小时前
数据结构---Map&Set
数据结构
南宫生12 小时前
力扣-数据结构-1【算法学习day.72】
java·数据结构·学习·算法·leetcode
yuanbenshidiaos12 小时前
数据结构---------二叉树前序遍历中序遍历后序遍历
数据结构
^南波万^12 小时前
数据结构--排序
数据结构