11-散列4 Hashing - Hard Version (30 分)(哈希+拓扑排序+优先队列)

9 篇文章 0 订阅
5 篇文章 0 订阅

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

题目大意:给定一串序列,是用哈希函数x%N存入数组中的,其中用线性探测解决冲突。如果是负数,表示该位置没有数字。现在要求这串序列输入的顺序是什么。如果有的数顺序并列,则从小到大输出。(根据数据和哈希值求输入顺序)

分析:如果某个数a的哈希值不是它的当前位置,并且这个哈希值处有数据b的话,说明b是在a前面输入的,这样二者求哈希值的时候,a就会冲突,然后线性探测,就被放到后面去了。

图示:
在这里插入图片描述

  1. 15%5==0,无冲突;
  2. 10%5==0,冲突了,探测一次,说明15是在10之前被输入的。在图中,用一条有向箭头表示先后关系;
  3. 7%5==2,无冲突;
  4. 5%5==0,冲突了,探测三次,说明15、10、7都是在5之前放进去的。

这样就构成了一个有向无环图DAG,所以要用到拓扑排序。

思路:

  1. 输入数据存入数组a[ ]中,并记录被存入的数字个数,以控制后续的输出格式;
  2. 根据给出的数据和哈希值构造DAG;
  3. 拓扑排序输出序列。由于在并列时,要从小到大输出,这里用到优先队列。

ps:

  1. 在进行建图和入队等操作时,对下标进行操作。我一开始是用的数据进行操作,由于没给数据的范围,而我的maxn又是1000,所以就出现了段错误……
  2. 题目说的是负数表示没有数字,而我一开始写的是-1表示没有……
  3. 在入队的时候,由于既要将将下标入队,又要将数据入队(方便输出),所以要用到pair。

代码如下:

#include <iostream>
#include <queue>
#define maxn 1000
using namespace std;
typedef pair<int, int> P;
int n, e[maxn][maxn], indegree[maxn], a[maxn];
void topsort(int cnt)
{
    int i;
    priority_queue<P, vector<P>, greater<P> >q;/*  最小堆  */
    for(i=0; i<n; i++)
        if(indegree[i] == 0)
            q.push(P(a[i], i));/*  把数据和下标入队  */
    int sum = 0;

	/*  拓扑排序核心部分  */
    while(!q.empty())
    {
        P x = q.top();
        q.pop();
        sum++;
        if(sum == cnt) cout << x.first << endl;
        else cout << x.first << " ";
        for(i=0; i<n; i++)
        {
            if(a[i] >= 0 && e[x.second][i] > 0)
            {
                if(--indegree[i] == 0)
                    q.push(P(a[i], i));
            }
        }
    }
}
int main()
{
    cin >> n;
    int i, j, cnt = 0;
    for(i=0; i<n; i++)
    {
        cin >> a[i];
        if(a[i] < 0) indegree[i] = -1;
        else
        {
            cnt++;
            indegree[i];
        }
    }
    for(i=0; i<n; i++)
    {
        if(a[i] >= 0)/*  如果有数字  */
        {
            for(j=0; (a[i]+j)%n !=i ;j++)/*  计算哈希值和线性探测同时进行  */
            {
                int pos = (a[i]+j) % n;
                e[pos][i] = 1;
                indegree[i]++;
            }
        }
    }
    topsort(cnt);
    return 0;
}


总结
  1. 在没有给数据范围的时候,对下标进行操作,避免段错误(数组越界等)。
  2. 第一次用到STL的优先队列和pair容器。
/*   优先队列   */
priority_queue<int>q  /* 默认大顶堆 */

priority_queue<int, vector<int>, greater<int> >q;/* 小顶堆 */
priority_queue<int, vector<int>, less<int> >q;/* 大顶堆 */
/* 要注意最后的位置是> >,不是>>,否则会编译错误 */

q.top()/*  在优先队列中,取队首元素不是q.front(),而是q.top()  */

/*   pair:包含<iostream>头文件就够了   */
pair<int, int>p;/*  可以理解为结构体,用一个变量存两个值  */

p.first;/*  访问p的第一个值  */
p.second;/*  访问p的第二个值 */   
  1. 优先队列和pair结合使用时,优先队列先排first的优先级;first相同时,排second的优先级。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值