哈希表设计
问题描述
针对某个集体(比如你所在的班级)中的“人名"设计一个哈希表,使得平均查找长度不超过 R,完成相应的建表和查表程序。
基本要求
假设人名为中国人姓名的汉语拼音形式。待填入哈希表的人名共有30个,取平均查找长度的上限为2。哈希函数用除留余数法构造,用伪随机探测再散列法处理冲突。
试验数据
取读者周围较熟悉的 30 个人的姓名。
实现提示
如果随机函数自行构造,则应首先调整好随机函数,使其分布均匀。人名的长度均不超过 19个字符(最长的人名如:庄双双(Zhang Shuangshuang)。字符的取码方法可直接利用C语言中的toascii 函数,并可对过长的人名先作折叠处理。
选作内容
- 从教科书上介绍的几种哈希函数构造方法中选出适用者并设计几个不同的哈希函数,比较它们的地址冲突率(可以用更大的名字集合作试验)
- 研究这30个人名的特点,努力找一个哈希函数,使得对于不同的拼音名一定不发生地址冲突。
- 在哈希函数确定的前提下尝试各种不同处理冲突的方法,考查平均查找长度的变化和造好的哈希表中关键字的聚簇性。
输入格式
第一行输入一个整数n (1 ≤ n ≤ 30),表示待填入哈希表的人名数量。
接下来的n行,每行输入一个字符串,表示一个人名。人名为中国人姓名的汉语拼音形式,长度不超过19个字符。
接着输入一个整数m (1 ≤ m ≤ 1e6),表示查询的次数。
接下来的m行,每行输入一个字符串,表示要查询的人名。
输出格式
输出m行,每行输出一个整数和一个字符串,表示查询的人名在哈希表中的位置。如果查询的人名不在哈希表中,则输出-1。
样例 #1
样例输入 #1
30
ZhangSan
LiSi
WangWu
ZhaoLiu
QianQi
SunBa
LiJiu
ZhouShi
WuYi
ZhengEr
WangSan
FengSi
ChenWu
ChuLiu
WeiQi
JiangBa
ShenJiu
LuoShi
HanYi
ZouEr
SongSan
HeSi
GengWu
HuangLiu
XuQi
GuoBa
MaoJiu
TianShi
CaoEr
DuSan
3
ZhaoLiu
GengWu
MaoJiu
样例输出 #1
ZhaoLiu 40
GengWu 49
MaoJiu 41
思路
实现一个哈希表,用于存储和查找人名。人名是以汉语拼音的形式表示的字符串。哈希表的大小是 MAX_SIZE,这是一个常数,值为60。哈希表由一个 HashTable 结构体表示,该结构体包含一个 ElemType 类型的数组 data 和一个 bitset 类型的数组 flag。data 用于存储人名,flag 用于标记哈希表中的位置是否已被占用。
哈希函数 calcHash 通过计算字符串中所有字符的ASCII值之和,然后对 MAX_SIZE 取余来计算哈希值。这是一种简单的除留余数法。
插入函数 insert 将一个元素插入哈希表。首先,计算元素的哈希值。然后,如果哈希值对应的位置已被占用,就使用伪随机探测再散列法找到一个新的位置。这种方法通过在当前哈希值的基础上加上一个随机数,然后对 MAX_SIZE 取余来计算新的哈希值。这个过程会一直重复,直到找到一个未被占用的位置。
查找函数 find 在哈希表中查找一个元素。首先,计算元素的哈希值。然后,如果哈希值对应的位置未被占用,或者被占用但存储的不是要查找的元素,就使用伪随机探测再散列法找到一个新的位置。这个过程会一直重复,直到找到要查找的元素,或者查找次数达到了上限 R。如果找到了要查找的元素,就返回其在哈希表中的位置,否则返回-1。
算法分析
insert 函数的时间复杂度是 O(1)O(1)O(1),这是因为哈希表的插入操作通常被认为是常数时间的。然而,如果发生冲突,那么需要进行再散列,这可能会增加时间复杂度。在最坏的情况下,如果所有的位置都发生冲突,那么时间复杂度将是 O(n)O(n)O(n),其中 nnn 是哈希表的大小。空间复杂度是 O(1)O(1)O(1),因为插入一个元素只需要固定的额外空间。
find 函数的时间复杂度也是 O(1)O(1)O(1),这是因为哈希表的查找操作通常被认为是常数时间的。然而,如果发生冲突,那么需要进行再散列,这可能会增加时间复杂度。在最坏的情况下,如果所有的位置都发生冲突,那么时间复杂度将是 O(n)O(n)O(n),其中 nnn 是哈希表的大小。空间复杂度是 O(1)O(1)O(1),因为查找一个元素只需要固定的额外空间。
代码
#include <algorithm>
#include <bitset>
#include <cstdlib>
#include <iostream>
#include <string>
#define AUTHOR "HEX9CF"
using namespace std;
using Status = int;
using ElemType = string;
const int N = 1e6 + 7;
const int TRUE = 1;
const int FALSE = 0;
const int OK = 1;
const int ERROR = 0;
const int INFEASIBLE = -1;
// const int OVERFLOW = -2;
const int MAX_SIZE = 60;
const int R = 2;
struct HashTable {
ElemType data[MAX_SIZE];
bitset<MAX_SIZE> flag;
};
int n, m;
ElemType a[N], b[N];
int calcHash(string x) {
int sum = 0;
for (const auto i : x) {
sum += i;
}
sum %= MAX_SIZE;
return sum;
}
Status insert(HashTable &ht, ElemType x) {
int h = calcHash(x);
while (ht.flag[h]) {
int d = rand() % MAX_SIZE;
h = (h + d) % MAX_SIZE;
}
// cout << x << " " << h << endl;
ht.flag[h] = 1;
ht.data[h] = x;
return OK;
}
int find(HashTable &ht, ElemType x) {
int h = calcHash(x);
int cnt = 0;
while (ht.flag[h] && ht.data[h] != x && cnt < R) {
int d = rand() % MAX_SIZE;
h = (h + d) % MAX_SIZE;
cnt++;
}
if (ht.data[h] == x) {
return h;
}
return -1;
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
cin >> m;
for (int i = 0; i < m; i++) {
cin >> b[i];
}
HashTable hashTable;
for (int i = 0; i < n; i++) {
insert(hashTable, a[i]);
}
for (int i = 0; i < m; i++) {
int idx = find(hashTable, b[i]);
cout << b[i] << " " << idx << "\n";
}
return 0;
}
】哈希表设计 题解(哈希表+位集合+除留余数法+伪随机探测法)&spm=1001.2101.3001.5002&articleId=139362179&d=1&t=3&u=5d48475fe3254fc88121b5289bd0fb2a)
3991

被折叠的 条评论
为什么被折叠?



