1. 什么是“开放寻址法”?
开放寻址法是一种解决哈希冲突的方法。当两个不同的键被映射到同一个桶时,开放寻址法会寻找下一个可用的空桶来存储数据。
- 例子:
- 键
"apple"
和"banana"
都被映射到桶5
。 - 如果桶
5
已经有数据了,开放寻址法会尝试找到下一个空桶(比如桶6
或桶7
)。
- 键
- 简单比喻:
- 想象一个停车场有很多停车位(桶),如果目标车位(桶)已经被占用了,就继续找下一个空车位。
2. 开放寻址法包含哪些部分?
- 哈希函数:将键转换成桶的位置。
- 探测方法:当发生冲突时,如何寻找下一个空桶。
- 常见方法:
- 线性探测:依次检查下一个桶。
- 二次探测:以平方数递增的方式检查桶。
- 双重哈希:使用第二个哈希函数计算步长。
- 常见方法:
- 存储数据:将键值对存储到找到的空桶中。
3. 背后到底做了哪些事情?
当你向数组中添加一个键值对时,PHP 的开放寻址法会执行以下步骤:
- 计算哈希值:通过哈希函数将键转换成一个数字。
- 找到对应的桶:根据哈希值确定数据应该存放在哪个桶。
- 检查冲突:如果这个桶已经有数据了,就按照探测方法寻找下一个空桶。
- 存储数据:将键值对存储到找到的空桶中。
4. 使用场景是什么?
- 快速查找:即使有冲突,也能通过探测方法快速找到目标数据。
- 小规模数据:适合桶的数量较少的情况。
- 避免链表开销:相比链表法,开放寻址法不需要额外的指针或链表结构。
5. 底层原理是什么?
开放寻址法的核心思想是:
- 哈希冲突处理:当多个键被映射到同一个桶时,通过探测方法寻找下一个空桶。
- 探测方法选择:
- 线性探测:简单但容易导致“聚集”问题(连续占用多个桶)。
- 二次探测:减少聚集问题,但实现稍复杂。
- 双重哈希:使用第二个哈希函数生成步长,分布更均匀。
- 动态扩展:当桶的利用率过高时,重新分配更多的桶以减少冲突。
6. 实际代码讲解
下面是一个模拟开放寻址法的简化代码示例,并附有详细注释:
<?php
// 模拟一个简单的开放寻址法哈希表类
class OpenAddressingHashTable {
private $buckets; // 存储桶的数组
private $size; // 哈希表的大小
public function __construct($size = 8) {
$this->buckets = array_fill(0, $size, null); // 初始化桶数组
$this->size = $size;
}
// 计算哈希值并找到对应的桶
private function hash($key, $attempt = 0) {
return (crc32($key) + $attempt) % $this->size; // 线性探测
}
// 添加键值对
public function set($key, $value) {
$attempt = 0; // 探测次数
while (true) {
$index = $this->hash($key, $attempt); // 计算当前桶位置
if ($this->buckets[$index] === null || $this->buckets[$index]['key'] === $key) {
// 如果桶为空或键相同,则存储数据
$this->buckets[$index] = ['key' => $key, 'value' => $value];
return;
}
$attempt++; // 尝试下一个桶
}
}
// 获取值
public function get($key) {
$attempt = 0; // 探测次数
while (true) {
$index = $this->hash($key, $attempt); // 计算当前桶位置
if ($this->buckets[$index] === null) {
return null; // 桶为空,说明键不存在
}
if ($this->buckets[$index]['key'] === $key) {
return $this->buckets[$index]['value']; // 找到键,返回值
}
$attempt++; // 尝试下一个桶
}
}
}
// 测试代码
$hashTable = new OpenAddressingHashTable();
$hashTable->set("apple", "red");
$hashTable->set("banana", "yellow");
echo "Apple: " . $hashTable->get("apple") . "\n"; // 输出 red
echo "Banana: " . $hashTable->get("banana") . "\n"; // 输出 yellow
注释详解
crc32($key)
:这是 PHP 内置的哈希函数,用于生成一个数字。$attempt
:探测次数,用于线性探测。while (true)
:循环直到找到空桶或匹配的键。$this->buckets[$index]
:存储或查找数据的桶。
7. 图示与思维导图
思维导图
开放寻址法
├── 输入
│ └── 键 (Key)
├── 处理
│ ├── 哈希函数计算桶位置
│ ├── 检查冲突
│ └── 探测空桶
└── 输出
└── 数据 (Value)
流程图
用户操作 -> 添加键值对 -> 哈希函数计算桶位置 -> 检查桶是否为空
↓ 是 -> 直接存储
↓ 否 -> 探测下一个桶 -> 找到空桶 -> 存储数据
示意图
桶 0: [key1 => value1]
桶 1: [key2 => value2]
桶 2: 空
桶 3: [key3 => value3]
...
桶 N: [key4 => value4]
UML 类图
+-----------------------------+
| OpenAddressingHashTable |
+-----------------------------+
| - buckets: array |
| - size: int |
+-----------------------------+
| + set(key, value) |
| + get(key): value |
+-----------------------------+
8. 总结
通过以上内容,我们可以看到开放寻址法是如何工作的。它就像一个聪明的停车管理员,当目标车位被占用时,会帮你找到下一个空车位。