PHP数组底层之开放寻址法到底是什么意思?

1. 什么是“开放寻址法”?

开放寻址法是一种解决哈希冲突的方法。当两个不同的键被映射到同一个桶时,开放寻址法会寻找下一个可用的空桶来存储数据。

  • 例子
    • "apple""banana" 都被映射到桶 5
    • 如果桶 5 已经有数据了,开放寻址法会尝试找到下一个空桶(比如桶 6 或桶 7)。
  • 简单比喻
    • 想象一个停车场有很多停车位(桶),如果目标车位(桶)已经被占用了,就继续找下一个空车位。

2. 开放寻址法包含哪些部分?

  1. 哈希函数:将键转换成桶的位置。
  2. 探测方法:当发生冲突时,如何寻找下一个空桶。
    • 常见方法:
      • 线性探测:依次检查下一个桶。
      • 二次探测:以平方数递增的方式检查桶。
      • 双重哈希:使用第二个哈希函数计算步长。
  3. 存储数据:将键值对存储到找到的空桶中。

3. 背后到底做了哪些事情?

当你向数组中添加一个键值对时,PHP 的开放寻址法会执行以下步骤:

  1. 计算哈希值:通过哈希函数将键转换成一个数字。
  2. 找到对应的桶:根据哈希值确定数据应该存放在哪个桶。
  3. 检查冲突:如果这个桶已经有数据了,就按照探测方法寻找下一个空桶。
  4. 存储数据:将键值对存储到找到的空桶中。

4. 使用场景是什么?

  • 快速查找:即使有冲突,也能通过探测方法快速找到目标数据。
  • 小规模数据:适合桶的数量较少的情况。
  • 避免链表开销:相比链表法,开放寻址法不需要额外的指针或链表结构。

5. 底层原理是什么?

开放寻址法的核心思想是:

  1. 哈希冲突处理:当多个键被映射到同一个桶时,通过探测方法寻找下一个空桶。
  2. 探测方法选择
    • 线性探测:简单但容易导致“聚集”问题(连续占用多个桶)。
    • 二次探测:减少聚集问题,但实现稍复杂。
    • 双重哈希:使用第二个哈希函数生成步长,分布更均匀。
  3. 动态扩展:当桶的利用率过高时,重新分配更多的桶以减少冲突。

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
注释详解
  1. crc32($key):这是 PHP 内置的哈希函数,用于生成一个数字。
  2. $attempt:探测次数,用于线性探测。
  3. while (true):循环直到找到空桶或匹配的键。
  4. $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. 总结

通过以上内容,我们可以看到开放寻址法是如何工作的。它就像一个聪明的停车管理员,当目标车位被占用时,会帮你找到下一个空车位。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值