题目简介
给定一个大小为N的哈希表,我们可以定义一个哈希函数H(x)=x%N。假设使用线性探测来解决冲突,我们可以很容易地得到哈希表的状态。这道题需要根据给定的哈希表的状态来重构输入序列,如果有多种选择,则选择较小的数排前面。
输入规范
每个输入文件包含一个测试用例。对于每个测试用例,第一行包含一个正整数N(≤1000),这是哈希表的大小。下一行包含N个整数,用空格分隔。一个负整数表示哈希表中的一个空单元格。保证所有非负整数在表中是不同的。
输出规范
对于每个测试用例,打印一行包含输入序列的代码,数字之间用空格隔开。注意,每一行的末尾必须没有额外的空间。
输入输出样例
分析
这道题我是一次确定输出序列的一个数字,具体的算法流程如下:
- 读入哈希表序列,统计插入序列的数字总数并找到第一次进行输出序列的数字,很明显,第一个数字为序列中无冲突插入的,且数值最小的。
- 遍历整个哈希表序列,统计每个位置的数的父节点,因为在插入该之前必须插入他的父节点,后续在判断是否可以插入时,只需要判断他有无父节点即可。
- 循环进行输出序列的确定,重复第一步的操作,找到无冲突插入的数值最小的点进行插入即可。
代码
写的有点混乱,思路的话是比较清晰的,因此还是一次过了。
#include<iostream>
#include<algorithm>
#include<list>
#include<string.h>
using namespace std;
const int INT_MAX = (1<<30);
const int MAX = 1010;
int Seq[MAX];
list<int> L[MAX];
int N;
int Result[MAX];
int visited[MAX];
struct Node
{
int value;
int ind;
};
Node Min;
int main()
{
int i;
cin >> N;
int cnt = 0;
Min.value = INT_MAX;
Min.ind = -1;
memset(visited, 1, sizeof(visited));
/*读入数据*/
for (i = 0; i < N; ++i)
{
cin >> Seq[i];
if (Seq[i] < 0)
continue;
cnt++;
visited[i] = 0;
if (Seq[i] < Min.value && (Seq[i] % N ==i))
{
Min.value = Seq[i];
Min.ind = i;
}
}
/*对父节点进行初始化*/
for (i = 0; i < N; ++i)
{
if (Seq[i] == -1)
continue;
int ind = Seq[i] % N;
if (ind != i)
{
while (ind != i)
{
if (Seq[ind] != -1)
L[i].push_front(ind);
if (ind <N-1)
ind++;
else if (ind == N-1)
ind = 0;
}
}
}
int k = 0;
int Root;
/*循环确定输出序列*/
while (k != cnt)
{
Result[k] = Min.value;
Root = Min.ind;
visited[Root] = 1;
for (i = 0; i < N; ++i)
{
if (L[i].empty())
continue;
int front = L[i].back();
if (front == Root)
{
L[i].pop_back();
}
else
{
list<int>::iterator it = L[i].end();
it--;
while (*it != Root&& it != L[i].begin())
{
it--;
}
if (*it == Root)
L[i].erase(it);
}
}
k++;
Min.value = INT_MAX;
Min.ind = -1;
for (i = 0; i < N; ++i)
{
if (!visited[i] && L[i].empty() && Seq[i] < Min.value)
{
Min.value = Seq[i];
Min.ind = i;
}
}
}
for (i = 0; i < cnt-1; ++i)
{
cout << Result[i] << " ";
}
cout << Result[cnt - 1] << endl;
return 0;
}