话不多说,直接上代码段
//
// 哈希表.c
// 哈希表
//
// Created by 贺学宇 on 2022/8/16.
//
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
typedef struct hash{
int value;
bool exit;
}hashtable;
void Inithash(hashtable*,int);
void ldm(int,hashtable*,int,int);
void sdm(int,hashtable*,int,int);
void hash_map(int,hashtable*,int,int,int);
int ASL_linear_success(hashtable*,int,int*,int,int);
int ASL_linear_defeat(hashtable*,int,int*,int,int);
int ASL_square_success(hashtable*,int,int*,int,int);
int ASL_square_defeat(hashtable*,int,int*,int,int);
void hash_print(hashtable*,int);
void ASL(hashtable*,int,int*,int,int,int);
void hash_creat(hashtable* ,int,int*,int,int,int);
void ASL(hashtable* H,int len_H, int *A,int len_A,int p,int choose){
printf("现在打印ASL\n");
if(choose == 1){
int a = ASL_linear_success(H, len_H, A, len_A, p);
float Asl_s = a/1.0/len_A;
int b = ASL_linear_defeat(H, len_H, A, len_A, p);
float Asl_d = b/1.0/p;
printf("线性探测的查找成功的平均查找长度为:%d/%d≈%f\n查找失败的平均查找长度为%d/%d≈%f\n",a,len_A,Asl_s,b,p,Asl_d);
}
else{
int c=ASL_square_success(H, len_H, A, len_A, p);
float Asl_s = c/1.0/len_A;
int d=ASL_square_defeat(H, len_H, A, len_A, p);
float Asl_d = d/1.0/p;
printf("二次探测的查找成功的平均查找长度为:%d/%d≈%f\n查找失败的平均查找长度为:%d/%d≈%f\n",c,len_A,Asl_s,d,p,Asl_d);
}
}
void hash_creat(hashtable* H,int len_H,int* A,int len_A,int p,int choose){//建立哈希表
int x;//记录当前输入的元素
printf("请输入哈希表中的元素\n");
for(int i=0;i<len_A;i++){
printf("请输入第%d个元素:",i+1);
scanf("%d",&x);
A[i]=x; //用数组A记录元素以便计算ASL
hash_map(x,H,len_H,p,choose); //将输入的元素映射到哈希表中
}
printf("哈希表建立完成\n");
}
void Inithash(hashtable* H,int len_H){ //哈希表的初始化
for(int i=0;i<len_H;i++){ //将哈希表的所有项的存在位都设置为false,表示当前表中无元素
H[i].exit=false;
}
}
void ldm(int x,hashtable *H,int len_H,int p){ //linear detection method线性探测法解决冲突
int n=x%p;
while(H[n].exit==true) //若当前位置上有元素,则线性探测
n=(n+1)%len_H;
if(H[n].exit==false){ //若当前位置上无元素,则赋值
H[n].value=x;
H[n].exit=true;
}
}
void sdm(int x,hashtable* H,int len_H,int p){ //square detection method二次探测法解决冲突
int n=x%p;
int i=0,s=0; //i是增量,s是增量i的平方
while(H[n].exit==true){ //若当前位置上存在元素,则线性探测
n=x%p;
if(s>0) //增量序列为 0 ,正负1的平方,正负2的平方……
s=0-s;
else
{ ++i;
s=pow(i,2);
}
n=(n+s+10*len_H)%len_H; //在数论中,-5%7=2即是(-5+k*7)%7
}
if(H[n].exit==false){ //若当前位置上无元素,则赋值
H[n].value=x;
H[n].exit=true;
}
}
void hash_map(int x,hashtable *H,int len_H,int p,int choose){//除留取余法映射
int n =x%p;
if(H[n].exit==false){ //若当前位置上无元素,则直接复制
H[n].value=x;
H[n].exit=true;
}
else //若当前位置上存在元素,则根据选择的冲突方法取解决冲突
switch(choose){
case 1:ldm(x,H,len_H,p);break;
case 2:sdm(x,H,len_H,p);break;
}
}
int ASL_linear_success(hashtable *H,int len_H,int *A,int len_A,int p){//线性探测法查找成功的总长度
int count; //记录当前位置查找成功的次数
int sum = 0; //记录查找成功的总长度
for(int i = 0;i<len_A;i++){
count = 0;
int n=A[i]%p;
while(H[n].exit==true){ //若当前位置有元素,则线性探测直到找到或者查找的位置为空
if(H[n].value==A[i]){ //若找到
count++;break;
}
else{ //找不到则线性探测
count++;n=(n+1)%len_H;
}
}
sum=count+sum;
}
return sum;
}
int ASL_linear_defeat(hashtable *H,int len_H,int *A,int len_A,int p){//线性探测查找失败的总长度
int count=0; //记录当前位置查找失败的次数
int sum = 0; //记录查找失败的总长度
for(int i = 0;i<p;i++){
count = 0;
int n=i;
while(H[n].exit==true){ //线性探测,直到被查找位置上没有元素
count++;n=(n+1)%len_H;
}
count++;
printf("当映射到:%d时,查找失败的长度为:%d\n",i,count);
sum=count+sum;
}
return sum;
}
int ASL_square_success(hashtable *H,int len_H,int *A,int len_A,int p){//平方探测法查找成功的总长度
int count; //记录当前位置查找成功的次数
int sum = 0; //记录查找成功的总长度
for(int i = 0;i<len_A;i++){
int s=0,j=0; //s是记录增量的平方,j是增量
count = 0;
int n=A[i]%p; //n是被查找元素的第一次映射的位置
while(H[n].exit==true){ //判断当前位置是不是被查找元素
if(H[n].value==A[i]){
count++;break; //若是,则记数加一并且直接跳出while循环
}
else{ //否则,进行二次探测,代码逻辑同sdm
n=A[i]%p;
if(s>0)
s=0-s;
else
{ ++j;
s=pow(j,2);
}
count++;
n=(n+s+10*len_H)%len_H;
}
}
sum=count+sum;
}
return sum;
}
int ASL_square_defeat(hashtable *H,int len_H,int *A,int len_A,int p){//二次探测的查找失败的查找长度
int count=0;
int sum = 0;
for(int i = 0;i<p;i++){
int s=0,j=0;
count = 0;
int n=i;
while(H[n].exit==true){ //一直进行二次探测直到被查找位置为空
n=i;
if(s>0)
s=0-s;
else
{ ++j;
s=pow(j,2);
}
if(j>len_H/2)break; //增量的取值应该小于表长的一半
count++;
n=(n+s+10*len_H)%len_H;
}
count++;
printf("当映射到%d时,查找失败的长度为:%d\n",i,count);
sum=count+sum;
}
return sum;
}
void hash_print(hashtable* H,int len_H){//打印哈希表
printf("根据您的输入建立的表为:\n");
for(int i=0;i<len_H;i++){
printf("%d ",i);
}
printf("\n");
for(int i=0;i<len_H;i++){
if(H[i].exit==true)
printf("%d ",H[i].value);
else
printf("NULL ");
}
printf("\n");
}
int main(){
int len_H;
printf("请输入你想要建立的哈希表的表长:");
scanf("%d",&len_H);
hashtable H[len_H];
printf("\n您输入的元素个数为:");
int len_A;
scanf("%d",&len_A);
int A[len_A]; //用来记录你所输入的序列,在计算ASL的时候会用到
int p;
printf("我们将使用除留取余法进行映射,请输入你所期望的质数P:");
scanf("%d",&p);
while(p>len_H||p<1){
printf("您输入的质数不合法,请重新输入:");
scanf("%d",&p);
}
Inithash(H,len_H);
int choose;//用来挑选解决冲突的函数
printf("1、线性探测法;2、平方探测法;\n请选择你想要解决冲突的函数:");
scanf("%d",&choose);
while(choose!=1&&choose!=2)//保证健壮性
{
printf("选择非法,请重新选择");
scanf("%d",&choose);
}
hash_creat(H,len_H,A,len_A,p,choose);//建立哈希表
hash_print(H,len_H); //打印哈希表
ASL(H, len_H, A, len_A, p, choose);//计算ASL
return 0;
}