离散数学问题——7-5 整型关键字的平方探测法散列(25 分)

902 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情 本题的任务很简单:将给定的无重复正整数序列插入一个散列表,输出每个输入的数字在表中的位置。所用的散列函数是 H(key)=key%TSize,其中 TSize 是散列表的表长。要求用平方探测法(只增不减,即H(Key)+i2)解决冲突。

注意散列表的表长最好是个素数。如果输入给定的表长不是素数,你必须将表长重新定义为大于给定表长的最小素数。

输入格式:

首先第一行给出两个正整数 MSize(≤104)和 N(≤MSize),分别对应输入的表长和输入数字的个数。随后第二行给出 N 个不重复的正整数,数字间以空格分隔。

输出格式:

在一行中按照输入的顺序给出每个数字在散列表中的位置(下标从 0 开始)。如果某个数字无法插入,就在其位置上输出 -。输出间以 1 个空格分隔,行首尾不得有多余空格。

输入样例:

4 4
10 6 4 15

输出样例:

0 1 4 -

代码长度限制   16 KB

时间限制     400 ms

内存限制     64 MB


PS:学过离散数学的同学对这题目还是比较了解的,不了解没关系
所谓线性探测即为余数+i²(i从0~表长)
如果超过了表长就没有意义了

思路分析:

  • 首先要做的是找一个比MSIZE大且最小的素数(如果MSIZE不是素数的话)
  • 我用的是比较简单的试除法
  • 由于是线性探测,我们之间使i从0开始加到MSIZE即可(按照离散数学的原理知道超过MSIZE就没有意义了)
  • 模拟

代码如下:

#include<iostream>
#include<string>
using namespace std;
const int N = 1e4 + 5;
bool a[N];

//找素数
bool Prime(int x) {
	if (x == 1 || x == 0)
		return false;
	for (int i = 2; i <= x / i; i++)
		if (x % i == 0)
			return false;
	return true;
}

//插入
void func(int x,int MSIZE) {
	//直接从0开始,直到表长(0即是直接找)
	for (int i = 0; i < MSIZE; i++) {
		if (!a[(x + i * i) % MSIZE]) {
			a[(x + i * i) % MSIZE] = true;
			cout << (x + i * i) % MSIZE;
			return;
		}
	}
	cout << '-';
}
int main()
{
	int MSIZE, n;
	cin >> MSIZE >> n;
	while (!Prime(MSIZE))
		MSIZE++;
	for (int i = 0; i < n; i++) {
		int x;
		cin >> x;
		if (i != 0)
			cout << " ";
		func(x, MSIZE);
	}
}

结果如下:

image.png PS:成功解题=理清思路+一定的技巧~