场景与痛点
假设内存中存在一批记录学号和姓名的结构体。如果已知一个学号,需要从中找出对应的姓名。
如果使用链表保存这些结构体,就必须遍历整个链表,逐个比较学号成员。这种方式效率较低,会浪费 CPU 资源和电力。相比之下,使用哈希表可以直接定位到目标结构体,无需遍历。
核心思路
本示例采用 C 语言实现哈希表,主要包含以下关键点:
- 哈希函数构建:使用除留余数法(Hash(key) = key % m),将键值映射到表地址。
- 冲突处理:采用开放定址法中的线性探测。当发生冲突时,向后查找下一个空闲位置。
- 空间管理:若预先不知道数组大小,可使用动态内存分配或
vector(在 C++ 中)替代全局数组。 - 性能评估:计算平均查找长度(ASL),作为衡量哈希表性能的重要指标。
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 元素类型定义 */
typedef struct {
int value; /* 元素值,学号 */
int hi; /* 冲突次数 */
char name[20]; /* 姓名 */
char sex; /* 性别 */
} DataType;
/* 哈希表类型定义 */
typedef struct {
DataType *data; /* 数据指针 */
int length; /* 哈希表的长度 */
int num; /* 表中元素个数 */
} HashTable;
/* 构造哈希表,并处理冲突 */
void CreateHashTable(HashTable *H, int m, int n) {
int i, sum, addr, di;
(*H).data = (DataType*)(m * (DataType));
(!(*H).data) ();
(*H).num = n;
(*H).length = m;
(i = ; i < m; i++) {
(*H).data[i].value = ;
(*H).data[i].hi = ;
(*H).data[i].sex = ;
}
(i = ; i < n; i++) {
sum = ;
addr = num[i] % m;
di = addr;
((*H).data[addr].value == ) {
(*H).data[addr].value = num[i];
(*H).data[addr].hi = ;
((*H).data[addr].name, name[i]);
(*H).data[addr].sex = sex[i];
} {
{
di = (di + ) % m;
sum += ;
} ((*H).data[di].value != );
(*H).data[di].value = num[i];
(*H).data[di].hi = sum + ;
((*H).data[di].name, name[i]);
(*H).data[di].sex = sex[i];
}
}
}
{
d, d1, m;
m = H.length;
d = d1 = v % m;
(H.data[d].value != ) {
(H.data[d].value == v) {
d;
} {
d = (d + ) % m;
}
(d == d1) {
;
}
}
;
}
{
average = ;
i;
(i = ; i < m; i++) {
average += H.data[i].hi;
}
average /= H.num;
(, average);
}
{
i;
();
(i = ; i < m; i++) (, i);
();
();
(i = ; i < m; i++) (, H.data[i].value);
();
();
(i = ; i < m; i++) (, H.data[i].hi);
();
();
(i = ; i < m; i++) (, H.data[i].sex);
();
();
(i = ; i < m; i++) (, H.data[i].name);
();
}
{
HashTable H;
pos, v;
num[] = {, , , , , , , };
* name[] = {, , , , , , , };
sex[] = {, , , , , , , };
m_TotalLen = ;
m_CurLen = ;
CreateHashTable(&H, m_TotalLen, m_CurLen);
DisplayHash(H, m_TotalLen);
() {
();
(, &v);
pos = SearchHash(H, v);
(pos == ) ;
(, v, pos, H.data[pos].name);
HashASL(H, m_TotalLen);
}
(H.data);
;
}

