Problem Description
The task of this problem is simple: insert a sequence of distinct positive integers into a hash table, and output the positions of the input numbers. The hash function is defined to be where is the maximum size of the hash table. Quadratic probing (with positive increments only) is used to solve the collisions.
Note that the table size is better to be prime. If the maximum size given by the user is not prime, you must re-define the table size to be the smallest prime number which is larger than the size given by the user.
Input Specification
Each input file contains one test case. For each case, the first line contains two positive numbers: (≤104) and (≤) which are the user-defined table size and the number of input numbers, respectively. Then distinct positive integers are given in the next line. All the numbers in a line are separated by a space.
Output Specification
For each test case, print the corresponding positions (index starts from 0) of the input numbers in one line. All the numbers in a line are separated by a space, and there must be no extra space at the end of the line. In case it is impossible to insert the number, print "-" instead.
Sample Input
4 4
10 6 4 15
Sample Output
0 1 4 -
Solution
题意理解:使用平方探测法插入数据并输出每个数据插入位置的下标,如果无法完成插入输出 - 表示无法插入。
使用开放地址法(仅正数的平方探测法)作为哈希表的冲突处理
程序框架:
- 创建哈希表
- 读入数据并插入
- 如果成功插入输出下标
- 否则输出
-
创建哈希表的步骤中规中矩,找大于元素数的最小质数,注意一开始最小值用例没过,在求最小素数时如果是 1 个元素则表长为 2 ,而不是去找下一个奇数
哈希表数组需要有两个域:数据和是否已经存储标识。
重点说一下平方探测法的实现:
- 在查找函数中先声明需要的变量
- OriPos 表示最开始哈希函数求出来的下标,初始化为哈希函数值
- NewPos 表示后来探测变化的下标,初始化为哈希函数值
- CNum 表示冲突次数,用来作为平方数的底数,初始化为 0
- 当哈希函数值所指地址的元素不为键值并且已经被插入了元素,进入循环
- CNum 加一
- NewPos 更新为 OriPos 加上 CNum 的平方
- 如果 NewPos 超出了表长需要求模来使其合法
- 如果发现某一次探测的新地址 NewPos 与最开始的地址 OriPos 相同了,说明出现周期而且还没有找到合适的位置插入,已经可以断定该键值无法插入,退出循环并返回 -1 表示无法插入
- 否则正常找到合适的 NewPos 会直接退出循环返回这个找到的地址
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
typedef struct LNode *PtrToLNode;
struct LNode {
int Data;
bool Info;
};
typedef struct TblNode *HashTable;
struct TblNode {
int TableSize;
PtrToLNode Element;
};
int NextPrime(int N)
{
int i, p;
if (N == 1) return 2;
p = (N % 2) ? N + 2 : N + 1;
while (p <= 1000000) {
for (i = (int)sqrt(p); i > 2; i--)
if (!(p % i)) break;
if (i == 2) break;
else p += 2;
}
return p;
}
HashTable CreateTable(int TableSize)
{
HashTable H;
int i;
H = (HashTable)malloc(sizeof(struct TblNode));
H->TableSize = NextPrime(TableSize);
H->Element = (PtrToLNode)malloc(sizeof(struct LNode) * H->TableSize);
for(i = 0; i < H->TableSize; i++) {
H->Element[i].Data = -1;
H->Element[i].Info = false;
}
return H;
}
int Hash(int key, int p)
{
return key % p;
}
int Find(HashTable H, int key)
{
int i, OriPos, NewPos, CNum;
CNum = 0;
OriPos = NewPos = Hash(key, H->TableSize);
while (H->Element[NewPos].Data != key && H->Element[NewPos].Info == true) {
CNum++;
NewPos = OriPos + CNum * CNum;
while (NewPos >= H->TableSize)
NewPos %= H->TableSize;
if (NewPos == OriPos) {
NewPos = -1;
break;
}
}
return NewPos;
}
bool Insert(HashTable H, int key)
{
int Pos;
Pos = Find(H, key);
if (Pos != -1) {
H->Element[Pos].Data = key;
H->Element[Pos].Info = true;
return true;
} else
return false;
}
void FreeTable(HashTable H)
{
free(H->Element);
free(H);
}
int main()
{
int i, MSize, N, num;
HashTable H;
scanf("%d%d", &MSize, &N);
H = CreateTable(MSize);
for (i = 0; i < N; i++) {
scanf("%d", &num);
if (Insert(H, num))
if (i) printf(" %d", Find(H, num));
else printf("%d", Find(H, num));
else
if (i) printf(" -");
else printf("-");
}
FreeTable(H);
return 0;
}