目录
题目描述
给定长度为 N 的散列表,处理整数最常用的散列映射是 H(x)=x%N。如果我们决定用线性探测解决冲突问题,则给定一个顺序输入的整数序列后,我们可以很容易得到这些整数在散列表中的分布。例如我们将 1、2、3 顺序插入长度为 3 的散列表HT[]
后,将得到HT[0]=3
,HT[1]=1
,HT[2]=2
的结果。
但是现在要求解决的是“逆散列问题”,即给定整数在散列表中的分布,问这些整数是按什么顺序插入的?
输入
输入的第一行是正整数 N(≤1000),为散列表的长度。第二行给出了 N 个整数,其间用空格分隔,每个整数在序列中的位置(第一个数位置为0)即是其在散列表中的位置,其中负数表示表中该位置没有元素。题目保证表中的非负整数是各不相同的。
输出
按照插入的顺序输出这些整数,其间用空格分隔,行首尾不能有多余的空格。注意:对应同一种分布结果,插入顺序有可能不唯一。例如按照顺序 3、2、1 插入长度为 3 的散列表,我们会得到跟 1、2、3 顺序插入一样的结果。在此规定:当前的插入有多种选择时,必须选择最小的数字,这样就保证了最终输出结果的唯一性。
输入样例
11
33 1 13 12 34 38 27 22 32 -1 21
输出样例
1 13 12 21 33 34 38 27 22 32
思路分析
这道题先给定整数在散列表中的分布,问这些整数是按什么顺序插入的?总体思路是:计算它本来应该放的位置suppose,和它实际放的位置fact。然后把所有数按升序排序(因为题目规定了有多种插入顺序时,必须选择最小的数字)。 从最小的并且还没有放进去的数开始,比较fact与suppose相同吗?相同就输出(代表放入散列表了),并且vistited置1。不相同就看suppose和fact之间的位置是否都visited==1,这种情况也可以输出并且vistited置1。 每放入一个数,都要重新从最小的数开始,在走一遍,一直到所有都visited==1了。
AC代码
#include<iostream>
#include<algorithm>
using namespace std;
class key{
public:
int data;
int fact;
int suppose;
key(){}
key(int d,int i,int n){
data=d;
fact=i;
suppose=d%n;
}
};
bool cmp(key a,key b){
return a.data<b.data;
}
int main(){
int n;
cin>>n;
int tab[n];
key hash[256];
int visited[256]={0};
int m=0;
for(int i=0;i<n;i++){
cin>>tab[i];
if(tab[i]==-1) visited[i]=1;
else{
hash[m]=key(tab[i],i,n);
m++;
}
}
sort(hash,hash+m,cmp);
while(1){
int flag=0;
for(int i=0;i<m;i++){
if(hash[i].fact==hash[i].suppose&&visited[hash[i].fact]==0){
cout<<hash[i].data<<" ";
visited[hash[i].fact]=1;
break;
}
int tag=1;
int cha=hash[i].fact-hash[i].suppose;
if(cha<0) cha=n+cha;
for(int j=hash[i].suppose,k=0;k<cha;j++,k++){
if(visited[j%n]==0){
tag=0;
}
}
if(tag==1&&visited[hash[i].fact]==0){
cout<<hash[i].data<<" ";
visited[hash[i].fact]=1;
break;
}
}
for(int i=0;i<n;i++){
if(visited[i]==0){
flag=1;
}
}
if(flag==0) break;
}
return 0;
}