C语言实现哈希函数

话不多说,直接上代码段

//
//  哈希表.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;
}

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值