哈希(散列)的概念:

https://blog.csdn.net/mowen_mowen/article/details/82943192

C语言实现:静态哈希表:

https://blog.csdn.net/mowen_mowen/article/details/82943371

C语言实现:动态哈希表

https://blog.csdn.net/mowen_mowen/article/details/82943932

解决哈希冲突有两种方法:

一:闭散列:

也叫开放地址法;当发生哈希冲突时,如果哈希表未装满,则可以把数据存放到下一个空位置中去

要想达到一个好的闭散列减小哈希冲突的目的;就对我们的的哈希函数的选择提出了要求:

常见的哈希函数有:

直接定制法 :

 取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B   优点:简单、均匀   缺点:需要事先知道关键字的分布情况   适合查找比较小且连续的情况  
除留余数法 : 

设散列表中允许的地址数为m,取一个不大于m,但接近或者等于m的质数p作为除数,按照哈希函数:Hash(key) = key % p(p<=m),将关键码转换成哈希地址  
平方取中法 :

假设关键字为1234,对它平方就是1522756,抽取中间的3位227作为哈希地址;   再比如关键字为4321,对它平方就是18671041,抽取中间的3位671(或710)作为哈希地址   平方取中法比较适合:不知道关键字的分布,而位数又不是很大的情况  
折叠法 :

折叠法是将关键字从左到右分割成位数相等的几部分(后一部分位数可以短些),然后将这几部分叠加求和,并按散列表表 长,取后几位作为散列地址   折叠法适合事先不需要知道关键字的分布,适合关键字位数比较多的情况  
随机数法 :

 选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key) = random(key),其中random为随机数函数   通常应用于关键字长度不等时采用此法

二:开散列法:

又叫链地址法(开链法);将具有相同哈希地址的元素归于同一个子集,每一个子集合称一个桶,各个桶中的元素通过一个单链表链接起来,各个链表的头结点存储在哈希表中,

具体情形如图:

底层构造:

#pragma oncetypedef int DataType;typedef struct HashNode
{struct HashNode* _pNext;    //指向下一个节点DataType _data;
}HashNode;typedef struct HashBucket
{HashNode**_table;      //指向哈希表的首位置int _capacity;int _size;
}HashBucket;void HashBucketInit(HashBucket *ht,int capacity);
void HashBucketInsertUnique(HashBucket* ht,DataType data);  //只能插入不同元素
void HashBucketInsertEqual(HashBucket* ht,DataType data);   //可以插入相同元素
void HashBucketDelereUnique(HashBucket* ht,DataType data);  //相同元素只删除一个
void HashBucketDelereEqual(HashBucket* ht, DataType data);  //删除所有相同元素
int HashBucketSize(HashBucket *ht);
int HashBucketEmpty(HashBucket *ht);
void HashBucketDestroy(HashBucket *ht);
void PrintfHashBucket(HashBucket* ht);

具体操作:

#include<stdio.h>
#include<windows.h>
#include<assert.h>
#include<malloc.h>int HashFunc(HashBucket *ht,DataType data)           //获得哈希地址(除留余数法)
{return data % ht->_capacity;
}HashNode* BuyHashNode(DataType data)                //获得节点(插入时使用)
{HashNode* pNewNode = (HashNode*)malloc(sizeof(HashNode));if (NULL == pNewNode){assert(0);return NULL;}pNewNode->_data = data;pNewNode->_pNext = NULL;return pNewNode;
}void HashBucketInit(HashBucket *ht,int capacity)         //初始化
{int i = 0;assert(ht);ht->_table = (HashNode**)malloc(sizeof(HashNode) * capacity );if (NULL == ht->_table){assert(0);return;}for (; i <=capacity; i++)ht->_table[i]=NULL;ht->_capacity = capacity;ht->_size = 0;
}void HashBucketInsertUnique(HashBucket* ht, DataType data)
{HashNode * pNewNode = NULL;//计算元素的桶号int bucketNo = HashFunc(ht, data);    //检测元素是否在当前桶中HashNode* pCur = ht->_table[bucketNo];while (pCur){if (data == pCur->_data)return;pCur = pCur->_pNext;}//创建新节点pNewNode = BuyHashNode(data); //头插pNewNode->_pNext = ht->_table[bucketNo];ht->_table[bucketNo] = pNewNode;ht->_size++;
}void HashBucketInsertEqual(HashBucket* ht, DataType data)
{HashNode *pNewNode = NULL;//计算元素的桶号int bucketNo = HashFunc(ht, data);//创建新节点pNewNode = BuyHashNode(data);//头插pNewNode->_pNext = ht->_table[bucketNo];ht->_table[bucketNo] = pNewNode;ht->_size++;
}void HashBucketDelereUnique(HashBucket* ht, DataType data)
{HashNode * pPre = NULL;//计算元素的桶号int bucketNo = HashFunc(ht, data);//检测元素是否在当前桶中HashNode* pCur = ht->_table[bucketNo];while (pCur){if (data == pCur->_data){if (pCur == ht->_table[bucketNo])           //是首元素{ht->_table[bucketNo] = pCur->_pNext;}else                                        //不是首元素{ pPre->_pNext = pCur->_pNext;}free(pCur);ht->_size--;return;}pPre = pCur;pCur = pCur->_pNext;}
}
void HashBucketDelereEqual(HashBucket* ht, DataType data)
{HashNode * pPre = NULL;//计算元素的桶号int bucketNo = HashFunc(ht, data);//检测元素是否在当前桶中HashNode* pCur = ht->_table[bucketNo];while (pCur){if (data == pCur->_data){if (pCur == ht->_table[bucketNo])           //是首元素{ht->_table[bucketNo] = pCur->_pNext;free(pCur);pCur = ht->_table[bucketNo];ht->_size--;}else                                        //不是首元素{pPre->_pNext = pCur->_pNext;free(pCur);pCur = pPre->_pNext;ht->_size--;}}pPre = pCur;pCur = pCur->_pNext;}
}int HashBucketSize(HashBucket *ht)
{printf("有效元素个数为:%d\n", ht->_size);return ht->_size;
}int HashBucketEmpty(HashBucket *ht)
{return 0 == ht->_size;
}void HashBucketDestroy(HashBucket *ht)
{int i = 0;for (; i < ht->_capacity; i++){HashNode*pCur = ht->_table[i];while (pCur){ht->_table[i] = pCur->_pNext;free(pCur);pCur = ht->_table[i];} }free(ht->_table);ht->_capacity = 0;ht->_size = 0;
}void PrintfHashBucket(HashBucket* ht)
{int i = 0;for (; i < ht->_capacity; i++){HashNode*pCur = ht->_table[i];printf("第%d号桶:  ", i);while (pCur){printf("%d--->",pCur->_data);pCur =pCur->_pNext;}printf("NULL\n");}}

进行测试

新建源文件:Hash.c

#include"HashBucket.h"int main()
{HashBucket ht;                    //创建HashBucketInit(&ht, 10);           //初始化HashBucketInsertEqual(&ht, 2);      //插入HashBucketInsertEqual(&ht, 3);HashBucketInsertEqual(&ht, 5);HashBucketInsertEqual(&ht, 8);HashBucketInsertEqual(&ht, 12);HashBucketInsertEqual(&ht, 13);HashBucketInsertEqual(&ht, 15);HashBucketInsertEqual(&ht, 25);HashBucketInsertEqual(&ht, 18);HashBucketInsertEqual(&ht, 28);PrintfHashBucket(&ht);                //打印HashBucketSize(&ht);HashBucketDelereUnique(&ht, 15);       //删除HashBucketDelereUnique(&ht, 5);HashBucketDelereUnique(&ht, 28);PrintfHashBucket(&ht);HashBucketSize(&ht);HashBucketDestroy(&ht);                 //销毁system("pause");return 0;
}

运行结果

第0号桶:  NULL
第1号桶:  NULL
第2号桶:  12--->2--->NULL
第3号桶:  13--->3--->NULL
第4号桶:  NULL
第5号桶:  25--->15--->5--->NULL
第6号桶:  NULL
第7号桶:  NULL
第8号桶:  28--->18--->8--->NULL
第9号桶:  NULL
有效元素个数为:10第0号桶:  NULL
第1号桶:  NULL
第2号桶:  12--->2--->NULL
第3号桶:  13--->3--->NULL
第4号桶:  NULL
第5号桶:  25--->NULL
第6号桶:  NULL
第7号桶:  NULL
第8号桶:  18--->8--->NULL
第9号桶:  NULL
有效元素个数为:7请按任意键继续. . .

哈希(散列):(四)C语言实现 哈希 开散列法相关推荐

  1. 【编程学习】浅谈哈希表及用C语言构建哈希表!

    哈希表:通过key-value而直接进行访问的数据结构,不用经过关键值间的比较,从而省去了大量处理时间. 哈希函数:选择的最主要考虑因素--尽可能避免冲突的出现 构造哈希函数的原则是: ①函数本身便于 ...

  2. 【C++】哈希——unordered系列容器|哈希冲突|闭散列|开散列

    文章目录 一.unordered系列关联式容器 二.哈希概念 三.哈希冲突 四.哈希函数 五.解决哈希冲突 1.闭散列--开放定址法 2.代码实现 3.开散列--开链法 4.代码实现 六.结语 一.u ...

  3. 【c++】哈希---unordered容器+闭散列+开散列

    1.unordered系列关联式容器 在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 logN,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也 ...

  4. 哈希之开散列,闭散列

    先从数据查找开始说起吧,在线性结构,树形结构当中查找一个元素必须经过多次和一些元素进行比较,然后通过比较,查找到对应元素,这种方法多多少少,时间复杂度都是比较高的. 有没有一种方法时间复杂度,仅仅O( ...

  5. C++:哈希(闭散列、开散列)

    文章目录 哈希概念 哈希冲突 哈希函数 哈希冲突解决 闭散列 什么时机增容,如何增容? 线性探测的实现 开散列 开散列增容 开散列的实现 开散列与闭散列比较 unordered_map模拟实现(应用开 ...

  6. 哈希 ---《哈希函数》------除数的选取为什么是质数?、《哈希冲突》------解决方法、《闭散列》、《开散列》

    一.哈希概念 顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较**.顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(logN ) ...

  7. C++---哈希闭散列与开散列

    产生原因 在顺序结构或树形结构的数据集合中,我们想要查询一个元素时,必须进行遍历,所以顺序结构的查询时间复杂度为O(N),树形结构查询的时间复杂度为O(log2^N),但是我们想要一种不用遍历就知道其 ...

  8. 【数据结构笔记39】哈希表/散列表、(数据关键字/字符串关键字)散列构造函数

    本次笔记内容: 11.1.1 引子:散列的基本思路 11.1.2 什么是散列表 11.2.1 数据关键词的散列函数构造 11.2.2 字符串关键词的散列函数构造 文章目录 散列表背景 基本思想引出 已 ...

  9. c++哈希(哈希表开散列实现)

    文章目录 0. 前言 1. 开散列 1.1 开散列概念 2. 开散列的代码实现 2.0 定义 2.1 插入实现--Insert 2.2 查找实现--Find 2.3 删除实现--Erase 2.4 仿 ...

最新文章

  1. html ajax put请求,javascript – PUT Ajax请求
  2. python3 deque(双向队列)
  3. 计算机科学软件工程专业大学排名,2020软件工程专业大学排名及录取分数汇总(2021理科生参考)...
  4. python3的print函数
  5. Nginx使用openssl生成证书文件
  6. [大数据之Yarn]——资源调度浅学
  7. Orleans解决并发之痛(四):Streams
  8. 下载keep运动软件_Keep运动软件官网下载_Keep运动最新官网下载_18183软件下载
  9. CodeForces Manthan 2011 D. Optical Experiment(动态规划)
  10. 鸿蒙硬件HI3861-OLED扫雷版本1
  11. ADO.NETv2.0的一些特征
  12. SEO行业应该如何给客户报价
  13. c语言二级考试程序设计题的做题步骤,计算机二级C语言上机考试操作步骤与流程.doc...
  14. vue 利用科大讯飞实现实时语音转写
  15. 在线靶场-墨者-安全意识1星-WEB页面分析
  16. 移动端页面布局方式,简单记录一下
  17. 智慧家庭解决方案-最新全套文件
  18. android TextView 分散对齐(两端对齐)
  19. 王者荣耀小游戏1.0震撼上线!C++版
  20. 事还得慢慢做,环境还得靠自己准备

热门文章

  1. 利用post-data来构造信息抓取艺龙酒店
  2. JGibbLDA使用总结
  3. 现代化生态灌区智慧灌溉管理系统方案介绍
  4. H5禁止页面滑动/滚动
  5. 职场情感录:办公室人际问题化解大法
  6. vc++ 德卡(IC卡)D3-U设密与读写应用
  7. LoS - 2D 视野、光影相关技术研究及分享
  8. c语言 压缩txt文件的函数,c语言 文本文件压缩
  9. python 图像处理
  10. 16.钩子事件hookEvent与插件。