PTA字符串关键字的散列映射【C++】

原题:
8.4 字符串关键字的散列映射
分数 29
作者 DS课程组
单位 浙江大学
给定一系列由大写英文字母组成的字符串关键字和素数P,用移位法定义的散列函数H(Key)将关键字Key中的最后3个字符映射为整数,每个字符占5位;再用除留余数法将整数映射到长度为P的散列表中。例如将字符串AZDEG插入长度为1009的散列表中,我们首先将26个大写英文字母顺序映射到整数0~25;再通过移位将其映射为 3 × 3 2 2 + 4 × 32 + 6 = 3206 3×32^2 +4×32+6=3206 3×322+4×32+6=3206;然后根据表长得到3206%1009=179,即是该字符串的散列映射位置。发生冲突时请用平方探测法解决。

输入格式:
输入第一行首先给出两个正整数N(≤500)和P(≥2N的最小素数),分别为待插入的关键字总数、以及散列表的长度。第二行给出N个字符串关键字,每个长度不超过8位,其间以空格分隔。

输出格式:
在一行内输出每个字符串关键字在散列表中的位置。数字间以空格分隔,但行末尾不得有多余空格。

输入样例1:

4 11
HELLO ANNK ZOE LOLI

输出样例1:

3 10 4 0

输入样例2:

6 11
LLO ANNA NNK ZOJ INNK AAA

输出样例2:

3 0 10 9 6 1

自己的思路:
num为当前探测的位置
hs[]标志是否已有元素,若无,则输出当前num,并令hs[num]为1;若产生冲突,使用平方探测法,依次探索。
漏洞:
题目中并未肯定

  1. 所有输入的关键字都有3位
  2. 关键字不重复
  3. 未处理在平方探测中 H i < 0 H_i<0 Hi<0的情况
#include<iostream>
#include<deque>
#include<math.h>
using namespace std;
int main() {
	int N, P;
	char t;
	int str[3]={1,32,1024};
	deque<char> arr;
	cin >> N >> P;
	getchar();//吸收回车
	int hs[P] = {0};//标志是否插入元素

	for (int i = 0; i < N; i++) {
		if(i!=0)
		cout<<' ';
		int num = 0;
		t = getchar();
		while (t != ' ' && t != '\n') {
			arr.push_front(t);//头插法
			t = getchar();
		}
		int p=0;
		for (deque<char>::iterator it = arr.begin(); p < 3; it++) {//取最后三位映射
			num += ((*it) - 'A') * str[p];
			p++;
		}
		num = num % P;

		if (hs[num] == 0) {//若不冲突
			cout << num;
			hs[num] = 1;
			if (i != N - 1)
				cout << " ";
		} else {//冲突
			int di = 1;//平方探测法
			int temp=num;
			while (hs[temp] == 1 || temp < 0) {
				temp = num;
				temp = (num + (int)pow(di, 2)) % P;
				if (hs[temp] == 1 || temp < 0) {
					temp = (num - (int)pow(di, 2)) % P;
				}
				di++;
			}
			cout << temp;
			hs[temp] = 1;
			if (i != N - 1)
				cout << " ";
		}
	}
}

改进代码

  1. 单独讨论关键字位数不足3的情况。
  2. 用一个unordered_map存储已有关键字。
  3. d i ( i ) < 0 使,令 H i = ( H ( k e y ) + d i ( i ) + P ) % P di(i)<0使,令H_i=(H(key)+di(i)+P)\%P di(i)<0使,令Hi=(H(key)+di(i)+P)%P,保证 H i H_i Hi始终>0
#include<iostream>
#include<unordered_map>//unordered_map头文件
#include<string.h>//memset头文件
#include<algorithm>//reverse头文件
#include<math.h>//pow头文件
using namespace std;
int GetHkey(string s, int m) { //获取H(key)
	reverse(s.begin(), s.end()); //翻转字符串
	int p = 0,sum = 0;
	for (auto i : s) {//当少于三个字符时,直接退出
		sum += (i - 'A') * pow(32, p);
		p++;
		if (p == 3)
			break;
	}
	return sum % m;
}
int main() {
	int N, P, num;
	cin >> N >> P;
	int Hash[P];
	memset(Hash, -1, sizeof(Hash));
	unordered_map<string, int>m;

	for (int i = 0; i < N; i++) {
		if (i != 0)
			cout << ' ';
		string s;
		cin >> s;
		if (m.count(s) == 1) {//若为重复关键字
			cout << m[s];
			continue;
		}
		num = GetHkey(s, P); //得到H(key)
		int k ,temp;
		k=1;temp=num;
		while (Hash[temp] != -1) {
			temp = num;
			if (k % 2 != 0) {//奇数为正
				temp = (temp + (int)pow((k + 1) / 2, 2)) % P;
			} else {//偶数为负
				temp = (temp - (int)pow((k + 1) / 2, 2) + P) % P;
			}
			k++;
		}
		Hash[temp] = 1;//存入temp位置
		m[s] = temp;
		cout << temp;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快苏排序OAO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值