鉴于博主很久没由跟新过数据结构的内容了,所以博主打算给大家讲解一下哈希表的操作

下面的内容来自于一位老司机 martin的源码,博主在这里借用一下,目的是突出哈希表的原理,明天博主就周末了,也能腾出时间来给上传自己的哈希表的应用。

这个是可以插入字符串的哈希表,一般的都是对数字的操作,所以这个的逼格是很高的!!!!(难点剖析放在最后)

#pragma once #define DEFAULT_SIZE 16 /*哈希表元素定义*/
typedef struct _ListNode{struct _ListNode *next;int key;void *data;
}ListNode;typedef ListNode *List;
typedef ListNode *Element;/*哈希表结构定义*/
typedef struct _HashTable{int TableSize;List *Thelists;
}HashTable;/*哈希函数*/
int Hash(void *key, int TableSize);/*初始化哈希表*/
HashTable *InitHash(int TableSize);/*哈希表插入*/
void Insert(HashTable *HashTable, int key,  void *value);/*哈希表查找*/
Element Find(HashTable *HashTable, const int key);/*哈希表销毁*/
void Destory(HashTable *HashTable);/*哈希表元素中提取数据*/
void *Retrieve(Element e);
hash_table.cpp#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include"hash_table.h"/*根据 key 计算索引,定位 Hash 桶的位置*/
int Hash(int key, int TableSize) { return (key%TableSize); //返回索引值}/*初始化哈希表*/
HashTable *InitHash(int TableSize){ //传入 哈希桶的个数,在函数内部给哈希表分配空间,再将初始化好了的哈希表传出去。int i = 0;HashTable *hTable = NULL;if (TableSize <= 0) {  //如果用户恶意输入数字,那么我们就可以把哈希表的个数定为我们最初的 16个TableSize = DEFAULT_SIZE;}hTable = (HashTable *)malloc(sizeof(HashTable));if (NULL == hTable){    //如果地址分配失败printf("HashTable malloc error.\n");return NULL;}hTable->TableSize = TableSize;//为 Hash 桶分配内存空间,其为一个指针数组 hTable->Thelists = (List *)malloc(sizeof(List)*TableSize);  //hTable->Thelists其实就是可以来指向哈希表里面的与元素了if (NULL == hTable->Thelists){  //分配空间失败,打印错误,然后返回printf("HashTable malloc error\n");free(hTable);return NULL;}//为 Hash 桶对应的指针数组初始化链表节点 for (i = 0; i < TableSize; i++){hTable->Thelists[i] = (ListNode *)malloc(sizeof(ListNode));//也就是给头节点分配空间地,这样后续就能完成插入了if (NULL == hTable->Thelists[i]){   //如果分配失败,那我们就释放之前分配了的空间地址,以免造成内存泄漏printf("HashTable malloc error\n");free(hTable->Thelists);free(hTable);return NULL;} else{memset(hTable->Thelists[i], 0, sizeof(ListNode));   //将好小标指向的元素全部清空。主要是防止意外情况。}}return hTable;
}Element Find(HashTable *HashTable, int key)
{int i = 0;  //目的接受调用HashTable函数返回的索引值List L = NULL;  //定位到(第几个哈希桶)指针数组里面的第几个头结点。Element e = NULL;  //指向定位到的(第几个哈希桶)的第一个节点(第一个节点是不包括头结点的哦)。i = Hash(key, HashTable->TableSize);L = HashTable->Thelists[i];e = L->next;while (e != NULL && e->key != key) //目的是为了遍历对应的哈希桶是否存在相同的key值。e = e->next;return e;   //返回两种情况,找到了就返回e对应的结构体,失败了就返回NULL
}/*哈希表插入元素,元素为键值对*/
void Insert(HashTable *HashTable, int key, void *value)
{Element e = NULL, tmp = NULL;   //e用来接收查找后的e,tmp是用来插入的List L = NULL;  //定位到第几个哈希桶,和我们的find中的L的作用是一样的。e = Find(HashTable, key);   //现在就找到了对应的第几个哈希桶的第一个节点了。或者是NULLif (NULL == e){ //如果接收到的e为空的话我们就可以进行插入元素的操作了tmp = (Element)malloc(sizeof(ListNode));   // 因为我们接收到的是NULL所以非配空间为了插入if (NULL == tmp){printf("malloc error\n");return;}L = HashTable->Thelists[Hash(key, HashTable->TableSize)];   //\定位到第几个哈希桶//经典的头插法tmp->data = value;tmp->key = key;tmp->next = L->next;L->next = tmp;} elseprintf("the key already exist\n");
}/*哈希表删除元素,元素为键值对*/
void Delete(HashTable *HashTable, int key){ //key是你要删除的第几个位置的键值对Element e = NULL, last = NULL;  List L = NULL;int i = Hash(key, HashTable->TableSize);    //找到对应的i是第几个L = HashTable->Thelists[i]; //找到对应的第几个哈希桶last = L;   //让last 等于 对应的第几个哈希桶的头结点e = L->next;    //e指向对应的第几个哈希桶的第一个节点。while (e != NULL && e->key != key) {    //遍历对应的哈希桶的全部链表,结束条件是 找到了要删除的key或者是遍历完成last = e;   //last为e也就是以后要删除的结点的上一个结点e = e->next;    //指向后面的结点}if (e) {//如果键值对存在,那么就可以删除了。last->next = e->next;   delete(e);}
}/*哈希表元素中提取数据*/
void *Retrieve(Element e)   //在元素e存在的情况下降找到的 e->data 返回出去
{return e ? e->data : NULL;  //三目运算符
}/*销毁哈希表*/
void Destory(HashTable *HashTable)
{int i = 0;List L = NULL;Element cur = NULL, next = NULL;for (i = 0; i < HashTable->TableSize; i++)  //将所有的哈希桶都遍历完成{L = HashTable->Thelists[i];cur = L->next;while (cur != NULL) //将对应的链表全部销毁,跳出之后只有头结点没有销毁了{next = cur->next;free(cur);cur = next;}free(L);    //释放那一个头结点}   //完成之后所有的哈希桶全部销毁free(HashTable->Thelists);  //释放那个二级指针free(HashTable);    //释放哈希表。
}int main(void)
{char  *elems[] = { "翠花","小芳","苍老师" };int i = 0;HashTable *HashTable;HashTable = InitHash(31);Insert(HashTable, 1, elems[0]);Insert(HashTable, 2, elems[1]);Insert(HashTable, 3, elems[2]);Delete(HashTable, 1);for (i = 0; i < 4; i++) {Element e = Find(HashTable, i);if (e) {printf("%s\n", (const char *)Retrieve(e));} else {printf("Not found [key:%d]\n", i);}}system("pause");return 0;
}

希望大家能好好的观看我的注释,相信一定能给你收获的。

如果觉得代码太长的,博主在这里给大家将模块分解了。大家也可以观看分解之后的代码,这样
压力会小一点。
头文件就不用说了相信大家都能看明白,就只是声明和定义结构体的类型而已。

哈希函数

/*根据 key 计算索引,定位 Hash 桶的位置*/
int Hash(int key, int TableSize) { return (key%TableSize); //返回索引值}

哈希表的初始化

/*初始化哈希表*/
HashTable *InitHash(int TableSize){ //传入 哈希桶的个数,在函数内部给哈希表分配空间,再将初始化好了的哈希表传出去。int i = 0;HashTable *hTable = NULL;if (TableSize <= 0) {  //如果用户恶意输入数字,那么我们就可以把哈希表的个数定为我们最初的 16个TableSize = DEFAULT_SIZE;}hTable = (HashTable *)malloc(sizeof(HashTable));if (NULL == hTable){    //如果地址分配失败printf("HashTable malloc error.\n");return NULL;}hTable->TableSize = TableSize;//为 Hash 桶分配内存空间,其为一个指针数组 hTable->Thelists = (List *)malloc(sizeof(List)*TableSize);  //hTable->Thelists其实就是可以来指向哈希表里面的与元素了if (NULL == hTable->Thelists){  //分配空间失败,打印错误,然后返回printf("HashTable malloc error\n");free(hTable);return NULL;}//为 Hash 桶对应的指针数组初始化链表节点 for (i = 0; i < TableSize; i++){hTable->Thelists[i] = (ListNode *)malloc(sizeof(ListNode));//也就是给头节点分配空间地,这样后续就能完成插入了if (NULL == hTable->Thelists[i]){   //如果分配失败,那我们就释放之前分配了的空间地址,以免造成内存泄漏printf("HashTable malloc error\n");free(hTable->Thelists);free(hTable);return NULL;} else{memset(hTable->Thelists[i], 0, sizeof(ListNode));   //将好小标指向的元素全部清空。主要是防止意外情况。}}return hTable;
}

哈希表中插入元素:

/*哈希表插入元素,元素为键值对*/
void Insert(HashTable *HashTable, int key, void *value)
{Element e = NULL, tmp = NULL;   //e用来接收查找后的e,tmp是用来插入的List L = NULL;  //定位到第几个哈希桶,和我们的find中的L的作用是一样的。e = Find(HashTable, key);   //现在就找到了对应的第几个哈希桶的第一个节点了。或者是NULLif (NULL == e){ //如果接收到的e为空的话我们就可以进行插入元素的操作了tmp = (Element)malloc(sizeof(ListNode));   // 因为我们接收到的是NULL所以非配空间为了插入if (NULL == tmp){printf("malloc error\n");return;}L = HashTable->Thelists[Hash(key, HashTable->TableSize)];   //\定位到第几个哈希桶//经典的头插法tmp->data = value;tmp->key = key;tmp->next = L->next;L->next = tmp;} elseprintf("the key already exist\n");
}

哈希表中查找元素:

Element Find(HashTable *HashTable, int key)
{int i = 0;  //目的接受调用HashTable函数返回的索引值List L = NULL;  //定位到(第几个哈希桶)指针数组里面的第几个头结点。Element e = NULL;  //指向定位到的(第几个哈希桶)的第一个节点(第一个节点是不包括头结点的哦)。i = Hash(key, HashTable->TableSize);L = HashTable->Thelists[i];e = L->next;while (e != NULL && e->key != key) //目的是为了遍历对应的哈希桶是否存在相同的key值。e = e->next;return e;   //返回两种情况,找到了就返回e对应的结构体,失败了就返回NULL
}

哈希表中删除元素:

/*哈希表删除元素,元素为键值对*/
void Delete(HashTable *HashTable, int key){ //key是你要删除的第几个位置的键值对Element e = NULL, last = NULL;  List L = NULL;int i = Hash(key, HashTable->TableSize);    //找到对应的i是第几个L = HashTable->Thelists[i]; //找到对应的第几个哈希桶last = L;   //让last 等于 对应的第几个哈希桶的头结点e = L->next;    //e指向对应的第几个哈希桶的第一个节点。while (e != NULL && e->key != key) {    //遍历对应的哈希桶的全部链表,结束条件是 找到了要删除的key或者是遍历完成last = e;   //last为e也就是以后要删除的结点的上一个结点e = e->next;    //指向后面的结点}if (e) {//如果键值对存在,那么就可以删除了。last->next = e->next;   delete(e);}
}

哈希表中提取元素以及销毁哈希表:

/*哈希表元素中提取数据*/
void *Retrieve(Element e)   //在元素e存在的情况下降找到的 e->data 返回出去
{return e ? e->data : NULL;  //三目运算符
}/*销毁哈希表*/
void Destory(HashTable *HashTable)
{int i = 0;List L = NULL;Element cur = NULL, next = NULL;for (i = 0; i < HashTable->TableSize; i++)  //将所有的哈希桶都遍历完成{L = HashTable->Thelists[i];cur = L->next;while (cur != NULL) //将对应的链表全部销毁,跳出之后只有头结点没有销毁了{next = cur->next;free(cur);cur = next;}free(L);    //释放那一个头结点}   //完成之后所有的哈希桶全部销毁free(HashTable->Thelists);  //释放那个二级指针free(HashTable);    //释放哈希表。
}

博主认为比较难的就是:
指针数组里面存放的是每个哈希桶的头结点,通过求余来锁定要查找或删除的值在哪一个哈希桶里(认为就是这个最难理解,理解了之后其实哈希就不难了)。其他的就是链表的操作了。

明天上传自己敲得代码

网络编程之 哈希表原理讲解 来自老司机的源码相关推荐

  1. Java:实现具有开放寻址冲突解析方法(如linear)的哈希表基类算法(附完整源码)

    Java:实现具有开放寻址冲突解析方法的哈希表基类算法 package com.williamfiset.algorithms.datastructures.hashtable;import java ...

  2. 基于linux epoll网络编程细节处理丨epoll原理剖析

    epoll原理剖析以及三握四挥的处理 1. epoll原理详解 2. 连接的创建与断开 3. epoll如何连接细节问题 视频讲解如下,点击观看: 基于linux epoll网络编程细节处理丨epol ...

  3. java毕业设计——基于Java+Java ME的无线网络移动端的俄罗斯方块游戏设计与实现(毕业论文+程序源码)——俄罗斯方块游戏

    基于Java+Java ME的无线网络移动端的俄罗斯方块游戏设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于Java+Java ME的无线网络移动端的俄罗斯方块游戏设计与实现,文章末尾附有 ...

  4. 服务器端编程心得(七)——开源一款即时通讯软件的源码

    服务器端编程心得(七)--开源一款即时通讯软件的源码 2017年04月06日 22:57:01 analogous_love 阅读数:30222更多 所属专栏: 高性能服务器编程实现细节详解 版权声明 ...

  5. java毕业设计——基于java+Jsoup+HttpClient的网络爬虫技术的网络新闻分析系统设计与实现(毕业论文+程序源码)——网络新闻分析系统

    基于java+Jsoup+HttpClient的网络爬虫技术的网络新闻分析系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+Jsoup+HttpClient的网络爬虫技术的网络 ...

  6. asp毕业设计——基于asp+sqlserver的网络教学评教管理信息系统设计与实现(毕业论文+程序源码)——教学评教管理信息系统

    基于asp+sqlserver的网络教学评教管理信息系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于asp+sqlserver的网络教学评教管理信息系统设计与实现,文章末尾附有本毕业设 ...

  7. 云原生服务网格Istio:原理、实践、架构与源码解析

    华为云原生团队600多页的Istio实战精华总结,云原生服务网格Istio:原理.实践.架构与源码解析的电子书. 图书介绍 <云原生服务网格Istio:原理.实践.架构与源码解析>分为原理 ...

  8. python3网络爬虫--爬取b站用户投稿视频信息(附源码)

    文章目录 一.准备工作 1.工具 二.思路 1.整体思路 2.爬虫思路 三.分析网页 1.分析数据加载方式 2.分词接口url 3.分析用户名(mid) 四.撰写爬虫 五.得到数据 六.总结 上次写了 ...

  9. 【通知】▁▂▃ Himi 最新著作《iOS游戏编程之从零开始—Cocos2d-x与cocos2d引擎游戏开发》★书籍源码+第4/5/6样章★-免费下载★ ▃▂▁

    2013年新年,Himi的第二本著作:<iOS游戏编程之从零开始-Cocos2d-x与cocos2d引擎游戏开发>一书正式发售: (大家可以到新华书店.淘宝.拍拍.当当.亚马逊等进行购买) ...

最新文章

  1. 从零开始写个编译器吧 - 单词化简述(Tokenization)
  2. python的用途实例-python中pass语句意义与作用(实例分析)
  3. Leetcode 45. 跳跃游戏 II (每日一题 20210922)
  4. 如何使用Prometheus采集SAP ABAP Netweaver的应用日志数据
  5. insert ... on duplicate key update产生death lock死锁原理
  6. Don't Laugh!I'm An English Book笔记(五)——面部词语大总结加补充
  7. asp.net调用js方法小结
  8. 2021高通人工智能创新大赛垃圾分类赛题第五次研讨会
  9. HDU 6241 Color a Tree
  10. mysql查找配置文件的顺序
  11. python-万年历
  12. VSCode配置vue用户代码片段Snippets
  13. 模拟CMOS集成电路学习笔记——MOS器件物理基础
  14. lisp 焊缝标注_钢结构深化设计实施方案.doc
  15. 按键精灵打怪学习-多线程后台坐标识别
  16. 电影推荐算法及python实现
  17. x86 单线并发多拨_OpenWrt ADSL单线多拨,负载均衡(仅供参考)
  18. flutter 刷脸_传说哥教你如何假装架构师
  19. Elasticsearch——Bboss
  20. html5程序员面试官如何提问,前端程序员第二轮面试的10个问题

热门文章

  1. 剑指offer之链表中倒数第K个节点
  2. 中国吉他效果市场趋势报告、技术动态创新及市场预测
  3. php5+init,PHP mysqli_stmt_init() 函数
  4. 标准IO库fgets和fputs对一个文本文件的读写操作
  5. Easystructure教程_C语言源代码自动生成流程图
  6. 历史上的今天:雅虎正式成立;PC 设计先驱诞生;Excite@Home 破产
  7. 放弃使用 15 年的 macOS,我决定换成 Linux!
  8. 程序员拒带电脑回家被开除获赔 19.4 万;库克称,很多功能来自中国消费者反馈;谷歌开源1.6万亿参数语言模型 | 极客头条...
  9. 什么是 “内存管理机制”?
  10. 挑战王者荣耀“绝悟” AI,会进化的职业选手太恐怖了!