PTA 7-18 Hashing - Hard Version 一个非拓扑排序的思路

Given a hash table of size , we can define a hash function . 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  (), which is the size of the hash table. The next line contains  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

 

思路:

记录一个非拓扑排序的简单思路,速度也还可以:

测试点 结果 分数 耗时 内存
0
答案正确
18 4 ms 328 KB
1
答案正确
4 4 ms 328 KB
2
答案正确
2 4 ms 332 KB
3
答案正确
2 5 ms 460 KB
4
答案正确
4 14 ms 456 KB

简单概括说,就是用一个堆和一个队列来回倒腾。

首先,堆是按照key的值大小的小顶堆,堆内每个元素都记录3个值:到hash表的索引 index ,key值 data ,按照给定hash函数本来该值所应该放的地址 shouldBe

用一个bool数组模拟记录hash表各位置上的元素是否已经插入;

将所有元素推入小顶堆,依次弹出,此时是按照key值大小由小到大弹出的;

每弹出一个元素,就检查其key值是否已经可以插入,判断依据:检查indexshouldBe之间的所有元素是否全部已经插入;

如果一个元素还不能插入,就推入普通队列里暂时存放,直到从minheap里弹出一个可以插入的元素,将这个元素输出之后,

再把这一轮所有推入普通队列的元素,重新插回minheap,进行下一轮的搜索;

另外,为了适当加速,在检查可行性函数bool checkAvail(Elem &)里,即使是对不可行的元素,也修改其 shouldBe指针,从而可以一定程度减少重复检查次数。

#include<iostream>
#include<vector>
#include<queue>
using namespace std;

constexpr int kMaxSize = 1024;
int tableSize;
struct Elem {
    int index, data, shouldBe;
    bool operator<(const Elem &e) const {
        return data > e.data;//min heap;
    }
};

bool inserted[kMaxSize]{};//by order of hashTable;
priority_queue<Elem> minHeap;
queue<Elem> que;//for temporary storing invalid elem;

bool checkAvail(Elem &elem){
    //backward check whether all clear between index and shouldBe;
    int idx = elem.shouldBe, stp = elem.index;
    while (idx != stp){
        if (inserted[idx] == false){
            elem.shouldBe = idx;//next time only need to check from crt blocking cell;
            return false;
        }
        idx = (idx + 1) % tableSize;//increment;
    }
    return true;
}

int main(){
    ios::sync_with_stdio(false);

    cin >> tableSize;
    Elem tmpE;
    for (int i = 0; i < tableSize; ++i){
        tmpE.index = i;
        cin >> tmpE.data;
        if (tmpE.data < 0){//regard empty cell as a clear loc;
            inserted[i] = true;
            continue;
        }
        tmpE.shouldBe = tmpE.data % tableSize;
        minHeap.push(tmpE);//O(logN);
    }

    bool fir = true;
    while (!minHeap.empty()){
        while (!minHeap.empty()){
            tmpE = minHeap.top();
            minHeap.pop();
            //if an elem is just at its right place, output it;
            if (tmpE.index == tmpE.shouldBe) break;
            else if (checkAvail(tmpE)) break;//if all blocked elem is cleared;
            //else : all temporarily-invalid elem are pushed into a queue;
            que.push(tmpE);
        }
        if (fir) fir = false;
        else cout << ' ';
        cout << tmpE.data;
        inserted[tmpE.index] = true;//regard as cleared;
        //push back into min heap for next loop checking;
        while (!que.empty()){
            tmpE = que.front();
            que.pop();
            minHeap.push(tmpE);//O(logN);
        }
    }
    return 0;
}

 

posted @ 2022-04-21 23:46  HarukiZ  阅读(97)  评论(0编辑  收藏  举报