09-3. Hashing - Hard Version

題目:

Given a hash table of size N, we can define a hash function H(x) = x%N. Suppose that the linear probing is used to solve collisions, we can easily obtain the status of the hash table with a given sequence of input numbers.

However, now you are asked to solve the reversed problem: reconstruct the input sequence from the given status of the hash table. Whenever there are multiple choices, the smallest number is always taken.

Input Specification:

Each input file contains one test case. For each test case, the first line contains a positive integer N (<=1000), which is the size of the hash table. The next line contains N integers, separated by a space. A negative integer represents an empty cell in the hash table. It is guaranteed that all the non-negative integers are distinct in the table.

Output Specification:

For each test case, print a line that contains the input sequence, with the numbers separated by a space. Notice that there must be no extra space at the end of each line.

Sample Input:
11
33 1 13 12 34 38 27 22 32 -1 21
Sample Output:
1 13 12 21 33 34 38 27 22 32

分析:上一個星期去幹別的了,當時剩了這最後一道題了,當時一直想不來,實在是無奈,所以過了一個星期纔回來繼續把它完成,在聽完姥姥的講解後,的確是很需要思考和分析能力的一道題。
題目的意思很簡單,仔細閱讀後(雖然也花了蠻久的,英語太差,怪我咯),還是能明白題意的,就是hash表的逆過程,也就是給出hash表序列和hash函數,需要你求出原始的序列,需要注意的是當有多個時,小的在前面(the smallest number is always taken.)。
這道題的代碼不是自己寫的,相似度很高,自己還需修行,太菜呀。
解題思路:
1.把Hash表的序列保存到數組中(我的習慣使用了vector,數組也一樣的)
2.計算入度,即衝突次數,並建立有向圖,把下標當頂點。從Key%N 到 當前下標 - 1的頂點都指向當前下標,因爲這些點都影響當前頂點。
3.拓撲排序,把度爲0的頂點放入最小堆中,STL可以用優先隊列。(STL真的是很好的工具)
4.找出度爲0且值最小的頂點,掃描與該點相連的頂點,入度 - 1,如果入度變0,則加入最小堆或者優先隊列。
5.取最小堆頂點或者取隊列首元素的時候,把該頂點的Key存入數組,當然你也可以直接輸出。

代碼:

#include<iostream>
#include<vector>
#include<queue>
#include<functional>

using namespace std;

int main()
{
	int N;
	cin >> N;		//輸入哈希表的大小
	int *Hash = new int[N];			//Hash數組
	int *Degree = new int[N];		//入度數組
	vector<vector<int>> G(N);		//無向圖  二維vector容器
	vector<int> Ans;				//輸出序列

	//輸入hash序列
	for (int i = 0; i < N; i++){
		cin >> Hash[i];
		if (Hash[i] > 0)
			Degree[i] = 0;
		else
			Degree[i] = -1;			//如果小於0,入度記爲-1,表示沒有元素
	}

	//計算入度並建立無向圖
	for (int i = 0; i < N; i++){
		if (Hash[i] < 0)
			continue;
		int curPos = i;				//當前座標
		int hashPos = Hash[i] % N;	//Hash後的座標
		Degree[i] = (curPos - hashPos + N) % N;	//計算入度,也就是衝突的次數
		for (int j = 0; j < Degree[i]; j++)
			G[(hashPos + j + N) % N].push_back(i);
	}

	//拓撲排序
	typedef pair<int, int> PAIR;
	priority_queue<PAIR, vector< PAIR >, greater< PAIR >> q;		//優先隊列
	for (int i = 0; i < N; i++){
		if (Degree[i] == 0){
			q.push(PAIR(Hash[i], i));
		}
	}
	
	while (!q.empty())
	{
		PAIR p = q.top();                       //每次取出當前入度爲0的頂點中Key最小的
		int V = p.second;                       //second爲頂點
		Ans.push_back(p.first);                 //first爲該頂點的Key
		q.pop();
		for (int i = 0; i < G[V].size(); i++)    //掃描關聯頂點,入度處理
			if (--Degree[G[V][i]] == 0)
				q.push(PAIR(Hash[G[V][i]], G[V][i]));
	}
	//輸出
	cout << Ans[0];
	for (int i = 1; i < Ans.size(); i++)
		cout << ' ' << Ans[i];

	return 0;
}


==================================================================================================================================

總結:最後一道題也結束了,通過這門課,pat的這些題,真的學到了很多東西,也發現了自己真的好菜呀,不過所有人一開始都是不懂得嘛,慢慢學。當然,同時發現,自己需要學的東西還有很多,真的好難呀,前面的這些題,真正自己做出來的真的沒幾個,很多都是通過查閱,google,百度呀出來的,所以還要好好修行,但也正是查閱過程中,感覺還是學會很多的知識的,比如STL,這真的是一個強大的工具,當然這個也不是萬能的哈,有些時候還是要自己寫最基礎的算法的。 ^_^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章