1078 Hashing (25 分)

题意

给出散列表长TSize和欲插入的元素,将这些元素按读入的顺序插入散列表中,其中散列函数为H(key) = key % TSize,解决冲突采用只往正向增加的二次探查法(即二次方探查法)。

另外,如果题目给出的TSize不是素数,那么需要将TSize重新赋值为第一个比TSize大的素数再进行元素插入。

样例解释

TSize为4,所以需要先找到比4大的第一个素数(即5),于是TSize = 5。接着插入四个元素:
key = 10,H(10) = 10%5 = 0,因此将10插入0号位。
key = 6,H(6) = 6%5 = 1,因此将6插入1号位。
key = 4,H(4) = 4%5 = 4,因此将4插入4号位。
key = 15,H(15) = 15%5 = 0,发生冲突;采用二次方探查法,H(15+1x1)=1,发生冲突;H(15+2x2)=4,发生冲突;H(15+3x3)=4,发生冲突;H(15+4x4)= 1,发生冲...可以证明,后面找不到一个不冲突的时点。

思路

  1. 首先,对于-一个输入的TSize,如果不是素数,则必须找到第一个比它大的素数。判断一个整数n是否是素数的方法:如果n不能被从2 ~Vn中的每-一个数整除,那么n是素数。
  2. 开一个bool型数组hashTable[],hashTable[key] == false 表示key号位未被使用。
    对每个插入的元素a,计算H(a)并判断对应位置是否被使用。
    • 如果未被使用,那么就找到可以插入的位置,并输出。
    • 如果已被使用, 根据二次方探查法,令步长step初值为1,然后令下一个检测值为(a+step * step) % TSize,判断该位置是否已被占用;如果已被占用,则令step++,再进行判断。step当自增达到TSize时如果还没有找到可用位置,则表明这个这个元素无法被插入(证明见注意点)。

注意点

  1. Quadratic probing是指二次方探查法,即当H(a)发生冲突时,让a按\(a+1^2,a-1^2,a+2^2,a-2^2,a+3^2,a-3^2...\)的顺序调整a的值。本题中已经说明只要往正向解决冲突,因此需要按\(a+1^2,a+2^2,a+2^3,...\)的顺序调整a的值
  2. 冲突处理公式是\(M=(a+step*step)%TSize\),注意要模上TSize。
  3. 1号测试点“答案错误”的原因是:判断质数时把1也当成了质数。
  4. 证明如果step从0 ~ TSize-1进行枚举却仍然无法找到位置,那么对step大于等于TSize来说也不可能找到位置(即证明循环节为TSize)。
    这里只需要证明当step取TSize至2TSize-1也无法找到位置即可:
    \(0 \le x \lt TSize\),那么
    (a + (TSize + x) * (TSize + x)) % TSize
    =(a + TSize * TSize+ 2 * TSize * x + x * x) % TSize
    =(a + x * x) % TSize + TSize * TSize % TSize + 2 * TSize * x % TSize
    =(a + x * x) % TSize
    由于所有循环节为TSize,如果step从0 ~ TSize-1进行枚举却仍然无法找到位置,那么对step大于等于TSize来说也不可能找到位置。
const int N=1e4+10;
bool vis[N];
int n,Tsize;

int find(int key)
{
    int k=key%Tsize;

    for(int i=0;i<Tsize;i++)
    {
        int t=(k+i*i)%Tsize;
        if(!vis[t]) return t;
    }
    return -1;
}

bool isprime(int x)
{
    if(x<2) return false;
    for(int i=2;i*i<=x;i++)
        if(x % i == 0)
            return false;
    return true;
}

int main()
{
    cin>>Tsize>>n;
    while(!isprime(Tsize)) Tsize++;
        
    for(int i=0;i<n;i++)
    {
        int x;
        cin>>x;
        int k=find(x);
        if(k != -1) 
        {
            vis[k]=true;
            if(i) cout<<' '<<k;
            else cout<<k;
        }
        else cout<<' '<<'-';
    }
    cout<<endl;
    //system("pause");
    return 0;
}
posted @ 2021-02-21 20:09  Dazzling!  阅读(45)  评论(0编辑  收藏  举报