Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[pull] main from itcharge:main #46

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
pull merged 8 commits into AlgorithmAndLeetCode:main from itcharge:main
Nov 3, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Update 01.Hash-Table.md
  • Loading branch information
itcharge committed Nov 3, 2022
commit d92fda32ab78cf636b7505d64283629da8a58cec
31 changes: 16 additions & 15 deletions Contents/05.Hash-Table/01.Hash-Table.md
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
## 1. 哈希表简介

> **哈希表(Hash Table)**:也叫做散列表。是根据关键码值(Key Value)直接进行访问的数据结构。也就是说,它通过键 `key` 和一个映射函数 `Hash(key)` 计算出对应的值 `value`,把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做「哈希函数(散列函数)」,存放记录的数组叫做「哈希表(散列表)」。
> **哈希表(Hash Table)**:也叫做散列表。是根据关键码值(Key Value)直接进行访问的数据结构。
>
> 哈希表通过「键 `key` 」和「映射函数 `Hash(key)` 」计算出对应的「值 `value`」,把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做「哈希函数(散列函数)」,存放记录的数组叫做「哈希表(散列表)」。

哈希表的关键思想是使用哈希函数,将键 `key` 映射到对应表的某个区块中。我们可以将算法思想分为两个部分:

- 向哈希表中插入一个关键字:哈希函数决定该关键字的对应值应该存放到表中的哪个区块,并将对应值存放到该区块中。
- 在哈希表中搜索一个关键字:使用相同的哈希函数从哈希表中查找对应的区块,并在特定的区块搜索该关键字对应的值。
- **向哈希表中插入一个关键码值**:哈希函数决定该关键字的对应值应该存放到表中的哪个区块,并将对应值存放到该区块中。
- **在哈希表中搜索一个关键码值**:使用相同的哈希函数从哈希表中查找对应的区块,并在特定的区块搜索该关键字对应的值。

哈希表的原理示例图如下所示:

![](https://qcdn.itcharge.cn/images/20220114120000.png)

在上图例子中,我们使用 `value = Hash(key) = key // 1000` 作为哈希函数。`//` 符号代表整除。我们以这个例子来说明一下哈希表的插入和查找策略。

- 插入:通过哈希函数解析关键字,并将对应值存放到该区块中。
- **向哈希表中插入一个关键码值**:通过哈希函数解析关键字,并将对应值存放到该区块中。
- 比如:`0138` 通过哈希函数 `Hash(key) = 0138 // 100 = 0`,得出应将 `0138` 分配到`0` 所在的区块中。
- 查找:通过哈希函数解析关键字,并在特定的区块搜索该关键字对应的值。
- **在哈希表中搜索一个关键码值**:通过哈希函数解析关键字,并在特定的区块搜索该关键字对应的值。
- 比如:查找 `2321`,通过哈希函数,得出 `2321` 应该在 `2` 所对应的区块中。然后我们从 `2` 对应的区块中继续搜索,并在 `2` 对应的区块中成功找到了 `2321`。
- 比如:查找 `3214`,通过哈希函数,得出 `3214` 应该在 `3` 所对应的区块中。然后我们从 `3` 对应的区块中继续搜索,但并没有找到对应值,则说明 `3214` 不在哈希表中。

Expand All @@ -29,8 +31,8 @@

- 存放所有拼音和对应地址的表可以看做是 **「哈希表」**。
- `赞` 字的拼音索引 `zan` 可以看做是哈希表中的 **「关键字 `key`」**。
- 根据拼音索引 `zan` 可以确定字对应页码的过程可以看做是哈希表中的 **「哈希函数 `Hash(key)`」**。
- 所查找到的对应页码 `599` 可以看做是哈希表中的 **「哈希地址 `value`」**。
- 根据拼音索引 `zan` 来确定字对应页码的过程可以看做是哈希表中的 **「哈希函数 `Hash(key)`」**。
- 查找到的对应页码 `599` 可以看做是哈希表中的 **「哈希地址 `value`」**。

## 2. 哈希函数

Expand All @@ -49,22 +51,21 @@

### 2.1 直接定址法

- 直接定址法:取关键字或者关键字的某个线性函数值为哈希地址。即:`Hash(key) = key` 或者 `Hash(key) = a * key + b`,其中 `a` 和 `b` 为常数。
- **直接定址法**:取关键字本身 / 关键字的某个线性函数值 作为哈希地址。即:`Hash(key) = key` 或者 `Hash(key) = a * key + b`,其中 `a` 和 `b` 为常数。

这种方法计算最简单,且不会产生冲突。适合于关键字分布基本连续的情况,如果关键字分布不连续,空位较多,则会造成存储空间的浪费。

举一个例子,假设我们有一个记录了从 `1` 岁到 `100` 岁的人口数字统计表。其中年龄为关键字,哈希函数取关键字自身,如下表所示。

| 地址 | 01 | 02 | 03 | ... | 25 | 26 | 27 | ... | 100 |
| :--: | :--: | :--: | :--: | :-: | :--: | :-: | :-: | :-: | :-: |
| 人数 | 3000 | 2000 | 5000 | ... | 1050 | ... | ... | ... | ... |
| 年龄 | 1 | 2 | 3 | ... | 25 | 26 | 27 | ... | 100 |
| 年龄 | 1 | 2 | 3 | ... | 25 | 26 | 27 | ... | 100 |
| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: |
| 人数 | 3000 | 2000 | 5000 | ... | 1050 | ... | ... | ... | ... |

比如我们想要查询 `25` 岁的人有多少,则只要查询表中第 `25` 项即可。

### 2.2 除留余数法

- 除留余数法:假设哈希表的表长为 `m`,取一个不大于 `m` 但接近或等于 `m` 的质数 `p`,利用取模运算,将关键字转换为哈希地址。即:`Hash(key) = key % p`,其中 `p` 为不大于 `m` 的质数。
- **除留余数法**:假设哈希表的表长为 `m`,取一个不大于 `m` 但接近或等于 `m` 的质数 `p`,利用取模运算,将关键字转换为哈希地址。即:`Hash(key) = key % p`,其中 `p` 为不大于 `m` 的质数。

这也是一种简单且常用的哈希函数方法。其关键点在于 `p` 的选择。根据经验而言,一般 `p` 取素数或者 `m`,这样可以尽可能的减少冲突。

Expand All @@ -76,14 +77,14 @@

### 2.3 平方取中法

- 平方取中法:先通过求关键字平方值的方式扩大相近数之间的差别,然后根据表长度取关键字平方值的中间几位数为哈希地址。
- **平方取中法**:先通过求关键字平方值的方式扩大相近数之间的差别,然后根据表长度取关键字平方值的中间几位数为哈希地址。
- 比如:`Hash(key) = (key * key) // 100 % 1000`,先计算平方,去除末尾的 2 位数,再取中间 3 位数作为哈希地址。

这种方法因为关键字平方值的中间几位数和原关键字的每一位数都相关,所以产生的哈希地址也比较均匀,有利于减少冲突的发生。

### 2.4 基数转换法

- 基数转换法:将关键字看成另一种进制的数再转换成原来进制的数,然后选其中几位作为哈希地址。
- **基数转换法**:将关键字看成另一种进制的数再转换成原来进制的数,然后选其中几位作为哈希地址。
- 比如,将关键字看做是 `13` 进制的数,再将其转变为 `10` 进制的数,将其作为哈希地址。

以 `343246` 为例,哈希地址计算方式如下:
Expand Down

AltStyle によって変換されたページ (->オリジナル) /