对于指定长度为N的整数数组,存储于指定长度为M的散列表中,使用指定的散列函数(使用简单的模素数P运算),若使用线性再散列(这里指的是:若冲突找下一个空位置)处理冲突,编程计算查找成功时平均查找长度和查找失败时的平均查找长度。
输入样例:
第一行三个整数,表示待存储的元素个数N,拟存储的散列表长度M和散列函数模除的素数P。第二行是N个以空格分隔的整数。
9 13 11
47 7 29 11 9 84 54 20 30
输出样例:
分别在两行中输出查找成功时平均查找长度和查找失败时的平均查找长度。 注意,请表达成总查找长度除以总查找次数的未约分形式(如:查找成功有10次,总共查找了30次,成功的平均查找长度为:30/10)。
23/9
41/11
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int N, M, P;
int sum1=0, sum2=0;
//散列单元状态类型,分别对应:有合法元素、空单元
typedef enum{Legitimate,Empty}EntryType;
typedef struct HashEntry Cell;
struct HashEntry {//散列表单元类型
int Data;//存放元素
EntryType Info;//单元状态
};
typedef struct TblNode* HashTable;//散列表类型
struct TblNode {//散列表节点定义
int TableSize;//表的最大长度
Cell* Cells;//存放散列单元数据的数组
};
HashTable CreateTable(int TableSize) {
HashTable H;
int i;
H = (HashTable)malloc(sizeof(struct TblNode));
H->TableSize = TableSize;
//声明单元数组
H->Cells = (Cell*)malloc(H->TableSize * sizeof(Cell));
//初始化单元状态为“空单元”
for (i = 0; i < H->TableSize; i++)
H->Cells[i].Info = Empty;
return H;
}
int Hash(int Key, int TableSize) {
int d = 1, temp;
temp = Key % P;//确定Key该放人的地址
if (temp < 0) {//如果Key为负数
temp = (temp + d) % TableSize;
d++;
}
return temp;
}
int Find(HashTable H, int Key) {
int CurrentPos, NewPos,d=1;
int CNum = 0;//记录冲突次数
NewPos = CurrentPos = Hash(Key, H->TableSize);//初始散列位置
//当该位置的单元非空,并且不是要找的元素时,发生冲突
while (H->Cells[NewPos].Info != Empty && H->Cells[NewPos].Data != Key) {
NewPos = (CurrentPos + d)%H->TableSize;//线性探索解决冲突
d++;
CNum++;
}
sum1 += (CNum + 1);//(每个插入元素的冲突次数+1)的总和=所有元素查找成功总次数
return NewPos;//此时NewPos或者是Key的位置,或者是一个空单元的位置(表示找不到)
}
bool Insert(HashTable H, int Key) {
int Pos = Find(H, Key);//先检测Key是否已经存在
if (H->Cells[Pos].Info != Legitimate) {
//如果这个单元没有被占,说明Key可以插入在此
H->Cells[Pos].Info = Legitimate;
H->Cells[Pos].Data = Key;
return true;
}
else//键值已经存在
return false;
}
void Check_fail(HashTable H,int P) {//统计查找失败时的总查找次数
int i,j,count;
for (i = 0; i < P; i++) {
//注意这里是从0到P,而不是从0到H->TableSize,也就是说只需统计散列函数能直接映射到的位置
if (H->Cells[i].Info == Empty)
sum2 =sum2+1;//如果查找位置为空则一次查找就可以确定查找位置为空
if(H->Cells[i].Info != Empty){
//如果查找位置不为空要从该元素位置开始查找到元素位置为空的位置才能确定查找失败
count = 0;
for (j = i; j < H->TableSize; j++) {//注意这里是在H->TableSize长度的散列表中查找
count++;
if (H->Cells[j].Info == Empty)
break;
if (j == H->TableSize - 1)
//若j达到H->TableSize - 1,让j置0,因为j是从i开始的i前面的元素还没统计
j = -1;//因为进入for循环的时候j++可以使j置0所以这里让j=-1
}
sum2 += count;//统计查找次数
}
}
}
int main() {
int i, j;
int Key;
HashTable H;
scanf("%d%d%d", &N, &M, &P);
H = CreateTable(M);
for (i = 0; i < N; i++) {
scanf("%d", &Key);
Insert(H, Key);
}
Check_fail(H,P);
printf("%d/%d\n", sum1, N);
printf("%d/%d", sum2, P);
system("pause");
return 0;
}