c语言哈希表电子辞典_哈希表的C语言实现

c语言哈希表电子辞典_哈希表的C语言实现构造一种存储结构 通过某种函数 hashFunc 使元素的存储位置与它的关键码之间能够建立一一映射的关系 那么在查找时通过该函数可以很快找到该元素 说到哈希表 首先就得说到哈希函数 哈希函数是用来得到给定 key 值的在哈希表中的存储位置的 哈希函数也并不是固定的 可以自己根据情况来定 一般常用常见的有直接定制法 除留余数法 平方取中法 折叠法 随机数法 数学分析法 当向该结构插入元素时 存入根据关键

构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。

说到哈希表,首先就得说到哈希函数,哈希函数是用来得到给定key值的在哈希表中的存储位置的。

哈希函数也并不是固定的,可以自己根据情况来定,一般常用常见的有直接定制法,除留余数法,平方取中法,折叠法,随机数法,数学分析法。

当向该结构插入元素时,存入根据关键码以此函数计算出的位置,当搜索时,也是先要将给定的关键码用函数转换成存储位置进行查找,将得到位置处的元素进行比较,若关键码相同,则搜索成功。

但是通过一个哈希函数得到的位置,一定是会有冲突的,

例如用除留余数法,哈希函数为key/100。在此情况下数字1与数字101得到的存储位置就是相同的,这样就是哈希冲突, 哈希冲突一般有两种解决方式,一种是闭散列,另一种是开散列。

闭散列(开放地址法):当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中还有空位,那就可以把key值存放到了列表的下一个空位。

开散列(链地址法):首先对关键码集合用哈希函数计算哈希表中的偏移位置,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。

hash.c

#include

#include

#include

#define BUCKETCOUNT 16

struct hashEntry

{

const char* key;

char* value;

struct hashEntry* next;

};

typedef struct hashEntry entry;

struct hashTable

{

entry bucket[BUCKETCOUNT]; //先默认定义16个桶

};

typedef struct hashTable table;

//初始化哈希表

void initHashTable(table* t)

{

int i;

if (t == NULL)return;

for (i = 0; i < BUCKETCOUNT; ++i) {

t->bucket[i].key = NULL;

t->bucket[i].value = NULL;

t->bucket[i].next = NULL;

}

}

//释放哈希表

void freeHashTable(table* t)

{

int i;

entry* e,*ep;

if (t == NULL)return;

for (i = 0; i

e = &(t->bucket[i]);

while (e->next != NULL) {

ep = e->next;

e->next = ep->next;

free(ep->key);

free(ep->value);

free(ep);

}

}

}

//哈希散列方法函数

int keyToIndex(const char* key)

{

int index , len , i;

if (key == NULL)return -1;

len = strlen(key);

index = (int)key[0];

for (i = 1; i

index *= + (int)key[i];

}

index >>= 27;

index &= (BUCKETCOUNT – 1);

return index;

}

//在堆上分配足以保存str的内存

//并拷贝str内容到新分配位置

char* strDup(const char* str)

{

int len;

char* ret;

if (str == NULL)return NULL;

len = strlen(str);

ret = (char*)malloc(len + 1);

if (ret != NULL) {

memcpy(ret , str , len);

ret[len] = ‘\0’;

}

return ret;

}

//向哈希表中插入数据

//insertEntry(&t , “电脑型号” , “华硕 X550JK 笔记本电脑”);

int insertEntry(table* t , const char* key , const char* value)

{

int index , vlen1 , vlen2;

entry* e , *ep;

if (t == NULL || key == NULL || value == NULL) {

return -1;

}

index = keyToIndex(key);

printf(“index = %d\n”,index);

if (t->bucket[index].key == NULL) {

t->bucket[index].key = strDup(key);

t->bucket[index].value = strDup(value);

}

else {

e = ep = &(t->bucket[index]);

while (e != NULL) { //先从已有的找

if (strcmp(e->key , key) == 0) {

//找到key所在,替换值

vlen1 = strlen(value);

vlen2 = strlen(e->value);

if (vlen1 > vlen2) {

free(e->value);

e->value = (char*)malloc(vlen1 + 1);

}

memcpy(e->value , value , vlen1 + 1);

return index; //插入完成了

}

ep = e;

e = e->next;

} // end while(e…

//没有在当前桶中找到

//创建条目加入

e = (entry*)malloc(sizeof (entry));

e->key = strDup(key);

e->value = strDup(value);

e->next = NULL;

ep->next = e;

}

return index;

}

//在哈希表中查找key对应的value

//找到了返回value的地址,没找到返回NULL

const char* findValueByKey(const table* t , const char* key)

{

int index;

const entry* e;

if (t == NULL || key == NULL) {

return NULL;

}

index = keyToIndex(key);

e = &(t->bucket[index]);

if (e->key == NULL) return NULL;//这个桶还没有元素

while (e != NULL) {

if (0 == strcmp(key , e->key)) {

return e->value; //找到了,返回值

}

e = e->next;

}

return NULL;

}

//在哈希表中查找key对应的entry

//找到了返回entry,并将其从哈希表中移除

//没找到返回NULL

entry* removeEntry(table* t , char* key)

{

int index;

entry* e,*ep; //查找的时候,把ep作为返回值

if (t == NULL || key == NULL) {

return NULL;

}

index = keyToIndex(key);

e = &(t->bucket[index]);

while (e != NULL) {

if (0 == strcmp(key , e->key)) {

//如果是桶的第一个

if (e == &(t->bucket[index])) {

//如果这个桶有两个或以上元素

//交换第一个和第二个,然后移除第二个

ep = e->next;

if (ep != NULL) {

entry tmp = *e; //做浅拷贝交换

*e = *ep;//相当于链表的头节点已经移除

*ep = tmp; //这就是移除下来的链表头节点

ep->next = NULL;

}

else {//这个桶只有第一个元素

ep = (entry*)malloc(sizeof(entry));

*ep = *e;

e->key = e->value = NULL;

e->next = NULL;

}

}

else {

//如果不是桶的第一个元素

//找到它的前一个(这是前面设计不佳导致的多余操作)

ep = &(t->bucket[index]);

while (ep->next != e)ep = ep->next;

//将e从中拿出来

ep->next = e->next;

e->next = NULL;

ep = e;

}

return ep;

}// end if(strcmp…

e = e->next;

}

return NULL;

}

void printTable(table* t)

{

int i;

entry* e;

if (t == NULL)return;

for (i = 0; i

printf(“\nbucket[%d]:\n” , i);

e = &(t->bucket[i]);

while (e->key != NULL) {

printf(“\t%s\t=\t%s\n” , e->key , e->value);

if (e->next == NULL)break;

e = e->next;

}

}

}

int main()

{

table t;

initHashTable(&t);

insertEntry(&t , “电脑型号” , “华硕 X550JK 笔记本电脑”);

insertEntry(&t , “操作系统” , “Windows 8.1 64位 (DirectX 11)”);

insertEntry(&t , “处理器” , “英特尔 Core i7 – 4710HQ @ 2.50GHz 四核”);

insertEntry(&t , “主板” , “华硕 X550JK(英特尔 Haswell)”);

insertEntry(&t , “内存” , “4 GB(Hynix / Hyundai)”);

insertEntry(&t , “主硬盘” , “日立 HGST HTSA9E680(1 TB / 5400 转 / 分)”);

insertEntry(&t , “显卡” , “NVIDIA GeForce GTX 850M (2 GB / 华硕)”);

insertEntry(&t , “显示器” , “奇美 CMN15C4(15.3 英寸)”);

insertEntry(&t , “光驱” , “松下 DVD – RAM UJ8E2 S DVD刻录机”);

insertEntry(&t , “声卡” , “Conexant SmartAudio HD @ 英特尔 Lynx Point 高保真音频”);

insertEntry(&t , “网卡” , “瑞昱 RTL8168 / 8111 / 8112 Gigabit Ethernet Controller / 华硕”);

insertEntry(&t , “主板型号” , “华硕 X550JK”);

insertEntry(&t , “芯片组” , “英特尔 Haswell”);

insertEntry(&t , “BIOS” , “X550JK.301”);

insertEntry(&t , “制造日期” , “06 / 26 / 2014”);

insertEntry(&t , “主人” , “就是我”);

insertEntry(&t , “价格” , “六十张红色毛主席”);

insertEntry(&t , “主硬盘” , “换了个120G的固态”);

entry* e = removeEntry(&t , “主板型号”);

if (e != NULL) {

puts(“找到后要释放”);

free(e->key);

free(e->value);

free(e);

e = NULL;

}

printTable(&t);

const char* keys[] = { “显示器” , “主人”,”没有” , “处理器” };

for (int i = 0; i < 4; ++i) {

const char* value = findValueByKey(&t , keys[i]);

if (value != NULL) {

printf(“find %s\t=\t%s\n” ,keys[i], value);

}

else {

printf(“not found %s\n”,keys[i]);

}

}

freeHashTable(&t);

getchar();

return 0;

}

标签:index,哈希,实现,value,C语言,key,NULL,ep

来源: https://www.cnblogs.com/vx-cg248805770/p/12881957.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/178725.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午4:37
下一篇 2026年3月26日 下午4:37


相关推荐

  • push master was rejected by remote(airpush)

    idea中,发布项目到OSChina的Git中,当时按照这样的流程添加Git,然后push,提示:pushtoorigin/masterwarrejected”。大概原因是:初始化项目时,远程仓库我建了README.md文件,而本地仓库与远程仓库尚未进行文件关联,因此需要将两个仓库的文件进行关联后提交。解决方案如下:1.切换到自己项目所在的目录,右键选择GITB…

    2022年4月13日
    212
  • 一阶倒立摆的PID_简单旋转装置

    一阶倒立摆的PID_简单旋转装置  我做PID算法的背景和经历:本人电子信息科学与技术专业,现在是一名大三的学生,对控制方向颇感兴趣,刚上大学时听到实验室老师说PID算法,那年在暑假集训准备全国电子设计竞赛,我正在练习做一个以前专科的题目,帆板角度控制系统,还不懂PID是个什么玩意,老师让我把PID加到这个题目里。当时给了一些电子版的一些教程,但是没看懂。。。。。。。后来对四旋翼很感兴趣,想弄一架玩玩再亲自写程序做一架,买了PI…

    2022年8月18日
    10
  • 讯飞智文

    讯飞智文

    2026年3月14日
    3
  • hive表数据去重

    hive表数据去重

    2021年5月13日
    151
  • 多节点服务器定时任务重复处理的问题

    多节点服务器定时任务重复处理的问题项目中有使用Spring定时执行任务的需求,用户可以自定义时间(半小时或整点)去生成需要的报表并发送邮件到用户自己的邮箱。项目里面提供的时间是半小时或整点去执行Spring定时任务,查询数据库中有哪些Schedule是满足要求的,然后去执行那些符合条件的任务。一切功能表现正常,但是项目部署在服务器上后,用户反映在同一时间会收到两封相同的邮件。我们检查了代码和SpringSchedule本

    2022年10月8日
    6
  • Pytest(1)安装与入门「建议收藏」

    Pytest(1)安装与入门「建议收藏」pytest介绍pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高。根据pytest的官方网站介绍,它

    2022年7月30日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号