哈希表查找

定义与基本思想

哈希表查找(Hash Table Search)是一种通过哈希函数将关键字映射到表中某个位置进行查找的方法。其核心思想是“以空间换时间”,查找效率极高。

哈希表查找演示

此处可扩展为哈希函数、冲突处理等动画。

  • 哈希函数映射
  • 冲突处理(开放定址/链地址)
  • 查找过程演示

适用场景

  • 适用于查找频繁、数据量较大的场合
  • 适用于对查找效率要求极高的应用

算法描述

  1. 设计合适的哈希函数 H(x)H(x),将关键字 xx 映射到哈希表的某个位置
  2. 若该位置为空,则查找失败
  3. 若该位置存有元素,比较关键字是否相等
  4. 若冲突,采用冲突处理方法(如开放定址法、链地址法)

伪代码如下:

pos = H(x)
if table[pos] == null:
    return -1
elif table[pos].key == x:
    return pos
else:
    // 冲突处理(如线性探测、链表查找等)
    ...

哈希函数的构造方法

  • 除留余数法:H(key)=key mod pH(key) = key \bmod p,p 取不大于表长 m 的最大素数,分布最均匀,最常用
  • 直接定址法:H(key)=a×key+bH(key) = a \times key + b,适合关键字分布连续
  • 数字分析法:取关键字中分布较均匀的若干位
  • 平方取中法:取关键字平方的中间几位
  • 折叠法:将关键字分割成若干段再相加

冲突处理方法

开放定址法

发生冲突时,在哈希表内寻找下一个空位。

  • 线性探测:Hi=(H(key)+i) mod mH_i = (H(key) + i) \bmod m,容易产生”堆积”
  • 平方探测:Hi=(H(key)+i2) mod mH_i = (H(key) + i^2) \bmod m,可避免堆积

链地址法

把哈希到同一位置的所有元素挂在同一条链表上。查找时先定位链表,再在链表中顺序查找。

#define M 13  // 哈希表长(取素数)

typedef struct Node {
    int key;
    struct Node *next;
} Node;

// 哈希函数:除留余数法
int H(int key) {
    return key % M;
}

// 链地址法查找
Node *HashSearch(Node *hashtable[], int key) {
    int pos = H(key);
    Node *p = hashtable[pos];
    while (p != NULL && p->key != key)
        p = p->next;          // 在链表中顺序查找
    return p;                 // 返回找到的结点或 NULL
}

// 链地址法插入
void HashInsert(Node *hashtable[], int key) {
    int pos = H(key);
    Node *s = (Node *)malloc(sizeof(Node));
    s->key = key;
    s->next = hashtable[pos];  // 头插法
    hashtable[pos] = s;
}

装填因子与性能分析

装填因子 α=表中元素个数表长\alpha = \frac{\text{表中元素个数}}{\text{表长}},它直接影响查找性能。

  • α\alpha 越大,冲突越多,查找效率越低
  • 链地址法的平均查找长度:ASL成功≈1+α2ASL_{成功} \approx 1 + \frac{\alpha}{2}
  • 线性探测的平均查找长度:ASL成功≈12(1+11−α)ASL_{成功} \approx \frac{1}{2}\left(1 + \frac{1}{1-\alpha}\right)
  • 工程实践中通常控制 α\alpha 在 0.7~0.8 以下

时间复杂度分析

  • 理想情况下:O(1)O(1)
  • 最坏情况下(大量冲突):O(n)O(n)
  • 实际应用中,查找效率接近 O(1)O(1)

习题

习题 1

哈希表查找的基本思想是什么?常见的冲突处理方法有哪些?

哈希表哈希函数冲突处理开放定址法

解题思路:

本题考查哈希表查找的基本原理与冲突处理方法。核心是两步:先用哈希函数把关键字直接映射到存储位置,再在发生冲突时按既定策略另寻位置存放。

详细步骤:

  1. 通过哈希函数将关键字映射到表中位置
  2. 冲突处理方法有开放定址法、链地址法等
  3. 补充:开放定址法在表内另找空位存放(如线性探测、二次探测),链地址法则把同址元素挂到同一条链表上;两者都是在保证查找效率的前提下应对“不同关键字映射到同一地址”的冲突。

最终答案:

哈希函数映射,冲突处理有开放定址、链地址法等。

习题 2

哈希表查找的平均时间复杂度是多少?在什么情况下会退化为 O(n)O(n)?

哈希表时间复杂度装填因子最坏情况

解题思路:

本题考查哈希表查找的平均效率及其退化条件。平均 O(1)O(1) 成立的前提是哈希函数分布均匀且装填因子不过大,一旦这两点被破坏,冲突链就会被拉长。

详细步骤:

  1. 平均复杂度 O(1)O(1)
  2. 当哈希函数设计不佳或装填因子过大,冲突严重时,最坏复杂度 O(n)O(n)
  3. 补充:平均 O(1)O(1) 成立于哈希函数分布均匀、冲突率较低的前提之下;装填因子(表中元素数与表长之比)越大冲突越频繁,查找实际上退化为沿冲突链逐个比较,最坏需要比较全部 nn 个元素。

最终答案:

平均 O(1)O(1),大量冲突时退化为 O(n)O(n)。

习题 3

哈希表查找的查找过程包括哪两步?常见的冲突处理方法有哪些?

哈希表查找过程冲突处理链地址法

解题思路:

本题考查哈希表查找的流程与冲突处理方法。查找过程固定为两步,第二步的具体做法取决于所选的冲突处理策略。

详细步骤:

  1. 通过哈希函数定位
  2. 冲突时采用开放定址或链地址法
  3. 补充:定位后若该位置存放的就是目标关键字则查找成功;否则说明发生了哈希冲突,需要按策略继续查找——开放定址法在该表中按探测序列继续找空位,链地址法则在对应的冲突链表上逐个比较,直到找到目标或确认不存在。

最终答案:

定位+冲突处理,方法有开放定址、链地址法等。

发现内容有问题?

告诉我们哪里需要改进。