PAT-ADVANCED1078/Data Structures and Algorithms7-17——Hashing

我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED

我的Data Structures and Algorithms代码仓:https://github.com/617076674/Data-Structures-and-Algorithms

原题链接:

PAT-ADVANCED1078:https://pintia.cn/problem-sets/994805342720868352/problems/994805389634158592

Data Structures and Algorithms7-17:https://pintia.cn/problem-sets/16/problems/679

题目描述:

PAT-ADVANCED1078、Data Structures and Algorithms7-17:

题目翻译:

1078 哈希

这个问题的任务很简单:在哈希表中插入一系列不同的正整数,并输出输入数字的位置。哈希函数被定义为H(密钥)= 密钥%TSize,其中TSize是散列表的最大大小。二次探测(仅具有正增量)用于解决冲突。

请注意,表的大小最好是素数。 如果用户给出的最大大小不是素数,则必须将表大小重新定义为一个素数,该素数是大于用户给出的大小的最小素数。

输入格式:

每个输入文件包含一个测试用例。对每个测试用例,第一行包含两个正整数:MSize(<= 10 ^ 4)和N(<= MSize),分别代表用户指定的哈希表的大小以及输入的数字数。加下来1行给出N个不同的正整数。一行中的所有数字由一个空格分隔。

输出格式:

对每个测试用例,在一行中打印出每个输入数字的位置(索引从0开始)。一行中的所有数字由一个空格分隔,行末不得有多余空格。如果没有位置可以插入该数字,输出“-”。

输入样例:

4 4
10 6 4 15

输出样例:

0 1 4 -

知识点:素数、哈希表

思路:处理好哈希冲突问题

Quadratic probing是指二次方探查法,即当H(a)发生冲突时,让a按a + 1 ^ 2,a - 1 ^ 2,a + 2 ^ 2,a - 2 ^ 2,a + 3 ^2,a - 3 ^ 2……的顺序调整a的值。本题中已经说明只要往正向解决冲突,因此需要按a + 1 ^ 2,a + 2 ^ 2,a + 3 ^ 2……的顺序调整a的值。

冲突处理公式是M = (a + step * step) % trueMSize。

证明:如果step从0 ~ trueMSize - 1进行枚举却仍然无法找到位置,那么对step大于等于trueMSize来说也不可能找到位置(即证明循环节为trueMSize)。

这里只需要证明当step取trueMSize至2 * trueMSize - 1也无法找到位置即可。

设0 <= x < trueMSize,那么

(a + (trueMSize + x) * (trueMSize + x)) % trueMSize

= (a + trueMSize * trueMSize + 2 * trueMSize * x + x * x) % trueMSize

= (a + x * x) % trueMSize + trueMSize * trueMSize % trueMSize + 2 * trueMSize * x % trueMSize

=(a + x * x) % trueMSize

由于所有循环节为trueMSize,如果step从0 ~ trueMSize - 1进行枚举却仍然无法找到位置,那么对是step大于等于trueMSize来说也不可能找到位置。 

时间复杂度最差情况下是O(N * trueMSize)。空间复杂度是O(trueMSize)。

C++代码:

#include<iostream>
#include<cmath>

using namespace std;

int findPrime(int num);	//寻找大于等于num的最小素数
bool isPrime(int num);	//判断一个数是否是素数

int main() {
	int MSize, N;
	scanf("%d %d", &MSize, &N);
	int trueMSize = findPrime(MSize);
	bool flag[trueMSize];
	fill(flag, flag + trueMSize, false);
	int num;
	int temp;
	for(int i = 0; i < N; i++) {
		scanf("%d", &num);
		temp = num % trueMSize;
		if(!flag[temp]) {
			printf("%d", temp);
			flag[temp] = true;
		} else {
			int j = 1;
			for(; j < trueMSize; j++) {
				temp = (j * j + num) % trueMSize;
				if(!flag[temp]) {
					printf("%d", temp);
					flag[temp] = true;
					break;
				}
			}
			if(j >= trueMSize){
				printf("-");
			}
		}
		if(i != N - 1) {
			printf(" ");
		}
	}
	return 0;
}

int findPrime(int num) {
	for(int i = num; ; i++) {
		if(isPrime(i)) {
			return i;
		}
	}
}

bool isPrime(int num) {
	if(num == 1) {
		return false;
	}
	for(int i = 2; i <= sqrt(num); i++) {
		if(num % i == 0) {
			return false;
		}
	}
	return true;
}

C++解题报告:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值