1. 程式人生 > >PAT-ADVANCED1078——Hashing

PAT-ADVANCED1078——Hashing

題目描述:

題目翻譯:

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++解題報告: