C语言写一个散列表

 更新时间:2022年01月04日 11:33:23   作者:微小冷  
这篇文章主要介绍了C语言写一个散列表,散列表,就是下标可以为字母的数组。更多内容和小编一起学习下面内容吧

一、快速理解散列表

散列表,就是下标可以为字母的数组。

假设现有一个数组int a[100],想查找其中第40个元素,则直接输入a[40]就可以了,时间复杂度为O ( 1 ) O(1)O(1)。

问题在于,当下标不是数字,而是一个字符串的时候,可能需要一个超大的空间才能将所有下标妥善地存放在特定的位置。例如,若以大小写字母作为下标索引,那么一位就需要预留52个空间,10位就需要52的10次方 这么大的空间,根本没有设备可以满足。

好在,52的10次方这么庞大的数字也超出了正常人的使用范围,无论多长的索引,我们能用上的值也绝对是有限的。

例如,现有下面三个字符串作为下标

key1 = "microcold";
key2 = "tinycold";
key3 = "microcool";

其实只需要选取头、尾两个字母,就能很好地区分这三个字符串,即

def hash(key):
    return key[0]+key[-1]

但这种算法对索引字符的要求非常高,至少头尾不能重复。所以,现在需要能把超长字符串映射成特定短字符串而且尽量避免重复的算法。

二、散列函数

最简单的散列函数就是求余,将输入字符串按位转为整数之后求余。由于在字符串可能会转成非常大的整数,故需了解余数的性质

(a+b)%c=(a%c+b %c)% c

相应地有:

(a*b)%c=((a%c)*(b %c))% c

用C语言实现如下:

#include <stdio.h>
#define MAXHASH 100

//快速取幂法,a*b^n%c
int  PowerMod (int a, int b, int n, int c) 
{  
    int  ans = 1; 
    b = b % c; 
    while (n > 0) {  
        if(n % 2 == 1) 
            ans = (ans * b) % c; 
        n = n / 2;       //b >>= 1;
        b = (b * b) % c; 
    } 
    return (a*ans)%c; 
} 

int hash(char* key, int n){
    int addr = 0;
    for(int i = 0; i < n; i++){
        addr += PowerMod(key[i], 128, i, MAXHASH);
    }
    return addr%MAXHASH;
}

int main(){
    char* str;
    int i;
    while(1){
        gets(str);
        i = 0;
        while(str[i++]!='\0'){}
        printf("%d\n",hash(str,i));
    }
    return 0;
}

测试如下:

>gcc hash.c
>a.exe
asdf
21
microcold
81
tinycold
12
microcool
5
minicool
81
minicold
73

三、防撞

尽管minicool和microcold撞车了,但通过100以内的位数,去表示52的9次方 的样本,也算是不错的表现了。

为了不发生撞车,则需更改数组中的元素类型——至少得是个结构体。而防止撞车的方法很简单,如果发生撞车,那我就不散列了,直接发配到一个指定的数组中。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXHASH 100
typedef struct HASHNODE{
    char *key;
    int next;
} *hashNode;

struct HASHNODE* hashTable[MAXHASH];
struct HASHNODE* crashTable[MAXHASH];     //存储撞击之后的值
int numCrash=0;                   //已有的撞击值

void initTable(){
    for(int i=0; i < MAXHASH; i++){
        hashTable[i] = (hashNode)malloc(sizeof(struct HASHNODE));
        hashTable[i]->key = NULL;
        hashTable[i]->next = -1;
        crashTable[i] = (hashNode)malloc(sizeof(struct HASHNODE));
        crashTable[i]->key = NULL;
        hashTable[i]->next = -1;
    }
}

void insertCrash(char* str, int index, int n){
    if(index == numCrash){
        crashTable[numCrash]->key = (char*)malloc(sizeof(char)*n);
        strcpy(crashTable[numCrash++]->key, str);  //此时新增一个节点
    }
    else {
        if(crashTable[index]->next==-1)
            crashTable[index]->next = numCrash;
        insertCrash(str, hashTable[index]->next, n);
    }
}

//n为字符串长度
void insertHash(char* str, int index,int n){
    if(hashTable[index]->key==NULL){
        hashTable[index]->key = (char*)malloc(sizeof(char)*n);
        strcpy(hashTable[index]->key, str);
    }else{
        if(hashTable[index]->next==-1)
            hashTable[index]->next = numCrash;
        insertCrash(str, hashTable[index]->next, n);
    }
}

void printHash(){
    for(int i = 0; i < MAXHASH; i++){
        if(hashTable[i]->key!=NULL)
            printf("hashTable[%d]:%s\n",i,hashTable[i]->key);
        if(crashTable[i]->key!=NULL)
            printf("crashTable[%d]:%s\n",i,crashTable[i]->key);
    }
}

int  PowerMod (int a, int b, int n, int c) 
{  
    int  ans = 1; 
    b = b % c; 
    while (n > 0) {  
        if(n % 2 == 1) 
            ans = (ans * b) % c; 
        n = n / 2;       //b >>= 1;
        b = (b * b) % c; 
    } 
    return (a*ans)%c; 
} 

int hash(char* key, int n){
    int addr = 0;
    for(int i = 0; i < n; i++){
        addr += PowerMod(key[i], 128, i, MAXHASH);
    }
    return addr%MAXHASH;
}

int main(){
    initTable();
    char* str;
    int i;
    while(1){
        gets(str);
        if(strcmp(str,"exit")==0) break;
        i = 0;
        while(str[i++]!='\0'){}
        insertHash(str,hash(str,i),i);
        printf("%d\n",hash(str,i));
    }
    printHash();
    return 0;
}

最后得到:

>gcc hash.c
>a.exe
asdf
21
hellworld
84
microcold
81
minicool
81
tinycool
20
tinycold
12
weixiaoleng
11
exit
crashTable[0]:minicool
hashTable[11]:weixiaoleng
hashTable[12]:tinycold
hashTable[20]:tinycool
hashTable[21]:asdf
hashTable[81]:microcold
hashTable[84]:hellworld

可见一方面的确散列了,另一方面也的确防撞了。

到此这篇关于C语言写一个散列表的文章就介绍到这了,更多相关C语言写散列表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言+EasyX实现数字雨效果

    C语言+EasyX实现数字雨效果

    这篇文章主要为大家详细介绍了C语言+EasyX实现数字雨效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-11-11
  • c语言定时器示例分享

    c语言定时器示例分享

    在linux下开发,使用的是C语言。适用于需要定时的软件开发,以系统真实的时间来计算,它送出SIGALRM信号。每隔一秒定时一次
    2014-04-04
  • C语言数据结构二叉树先序、中序、后序及层次四种遍历

    C语言数据结构二叉树先序、中序、后序及层次四种遍历

    这篇文章主要介绍了C语言数据结构二叉树先序、中序、后序及层次四种遍历方式,具有一定的知识性参考价值,需要的小伙伴可以先看一下
    2022-02-02
  • C语言实现用户态线程库案例

    C语言实现用户态线程库案例

    下面小编就为大家带来一篇C语言实现用户态线程库案例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • C++中list的用法实例讲解

    C++中list的用法实例讲解

    list是顺序容器的一种,list是一个双向链表,使用list需要包含头文件list,这篇文章主要给大家介绍了关于C++中list的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2021-11-11
  • 详解C++中的数据抽象

    详解C++中的数据抽象

    这篇文章主要介绍了详解C++中的数据抽象,数据抽象是指,只向外界提供关键信息,并隐藏其后台的实现细节,即只表现必要的信息而不呈现细节,需要的朋友可以参考下
    2023-05-05
  • QT实现自定义Http客户端的示例代码

    QT实现自定义Http客户端的示例代码

    这篇文章主要为大家详细介绍了QT如何实现自定义Http客户端的,可以实现支持get,post请求方式;支持连接超时处理;支持网络错误,尝试重连等功能,感兴趣的小伙伴可以学习一下
    2022-11-11
  • C语言实现动态顺序表的示例代码

    C语言实现动态顺序表的示例代码

    顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构。顺序表一般分为静态顺序表和动态顺序表,本文主要和大家介绍的是动态顺序表的实现,需要的可以参考一下
    2022-10-10
  • 基于Matlab图像处理的公路裂缝检测实现

    基于Matlab图像处理的公路裂缝检测实现

    随着公路的大量投运,公路日常养护和管理已经成为制约公路运营水平提高的瓶颈,特别是路面状态采集、检测维护等工作更是对传统的公路运维模式提出了挑战。这篇文章主要介绍了如何通过Matlab图像处理实现公路裂缝检测,感兴趣的可以了解一下
    2022-02-02
  • C++ 使用new与delete需注意的原则

    C++ 使用new与delete需注意的原则

    这篇文章主要介绍了C++ 使用new与delete需注意的原则,帮助大家更好的理解和学习c++,感兴趣的朋友可以了解下
    2020-08-08

最新评论