哈希表的C++实现(转)
哈希表的几个概念:
映像:由哈希函数得到的哈希表是一个映像。
冲突:如果两个关键字的哈希函数值相等,这种现象称为冲突。
处理冲突的几个方法:
1、开放地址法:用开放地址处理冲突就是当冲突发生时,形成一个地址序列,沿着这个序列逐个深测,直到找到一个“空”的开放地址,将发生冲突的关键字值存放到该地址中去。
例如:hash(i)=(hash(key)+d(i)) MOD m (i=1,2,3,......,k(k<m-1)) d为增量函数,d(i)=d1,d2,d3,...,dn-1
根据增量序列的取法不同,可以得到不同的开放地址处理冲突探测方法。
有线性探测法、二次方探测法、伪随机探测法。
2、链地址法:把所有关键字为同义词的记录存储在一个线性链表中,这个链表成为同义词链表,即把具有相同哈希地址的关键字值存放在同义链表中。
3、再哈希表:费时间的一种方法
下面是代码:
文件"myhash.h"
- #include<iostream>
- using namespace std;
- typedef int KeyType; //设关键字域为整形,需要修改类型时,只需修改这里就可以
- const int NULLKEY=0; //NULLKEY表示该位置无值
- int c=0; //用来统计冲突次数
- struct Elemtype //数据元素类型
- {
- KeyType key;
- int ord;
- };
- int hashsize[]={11,19,29,37,47}; //hash表容量递增表
- int Hash_length=0;//hash表表长
- class HashTable
- {
- private:
- Elemtype *elem; //数据元素数组,动态申请
- int count;// 当前数据元素个数
- int size; //决定hash表的容量为第几个,hashsize[size]为当前hash容量
- public:
- int Init_HashTable() //构造一个空hash表
- {
- int i;
- count=0;
- size=0; //初始化容量为hashsize[0]=11
- Hash_length=hashsize[0];
- elem=new Elemtype[Hash_length];
- if(!elem)
- {
- cout<<"内存申请失败"<<endl;
- exit(0);
- }
- for(i=0;i<Hash_length;i++)
- elem[i].key=NULLKEY;
- return 1;
- }
- void Destroy_HashTable()
- {
- delete[]elem;
- elem=NULL;
- count=0;
- size=0;
- }
- unsigned Hash(KeyType k) //hash函数的一种(取模法)
- {
- return k%Hash_length;
- }
- void Collision(int &p,int d) //解决冲突
- {
- p=(p+d)%Hash_length; //采用开放地址法里的线性探测
- }
- bool Search_Hash(KeyType k,int &p) //查找
- {
- //在开放地址hash表中查找关键字等于k的元素
- //若找到用p表示待查数据,查找不成功时,p指向的是可插入地址
- c=0;
- p=Hash(k); //求hash地址
- while(elem[p].key!=NULLKEY && elem[p].key!=k)
- {
- c++;
- if(c<Hash_length)
- Collision(p,c);
- else
- return 0; //表示查找不成功
- }
- if(elem[p].key==k)
- return 1;
- else
- return 0;
- }
- int Insert_Hash(Elemtype e) //插入
- {
- //在查找不成功的情况下将k插入到hash表中
- int p;
- if(Search_Hash(e.key,p))
- return -1; //表示该元素已在hash表中
- else if(c<hashsize[size]/2) //冲突次数未达到上限
- {
- //插入e
- elem[p]=e;
- count++;
- return 1;
- }
- else
- ReCreate_HashTable(); // 重建hash表
- return 0; //插入失败
- }
- void ReCreate_HashTable() //重建hash表
- {
- int i,count2=count;
- Elemtype *p,*elem2=new Elemtype[count];
- p=elem2;
- cout<<"____重建hash表_____"<<endl;
- for(i=0;i<Hash_length;i++) //将原有元素暂存到elem2中
- if(elem[i].key!=NULLKEY)
- *p++=*(elem+i);
- count=0;
- size++; //hash容量增大
- Hash_length=hashsize[size];
- p=new Elemtype[Hash_length];
- if(!p)
- {
- cout<<"空间申请失败"<<endl;
- exit(0);
- }
- elem=p;
- for(i=0;i<Hash_length;i++)
- elem[i].key=NULLKEY;
- for(p=elem2;p<elem2+count2;p++) //将原有元素放回新表
- Insert_Hash(*p);
- }
- void Traverse_HashTable()
- {
- cout<<"哈希地址0->"<<Hash_length-1<<endl;
- for(int i=0;i<Hash_length;i++)
- if(elem[i].key!=NULLKEY)
- cout<<"元素的关键字值和它的标志分别是:"<<elem[i].key<<" "<<elem[i].ord<<endl;
- }
- void Get_Data(int p)
- {
- cout<<"元素的关键字值和它的标志分别是:"<<elem[p].key<<" "<<elem[p].ord<<endl;
- }
- };
测试函数"main.cpp"
- #include"myhash.h"
- int main()
- {
- Elemtype r[12]={{17,1},{60,2},{29,3},{38,4},{1,5},{2,6},{3,7},{4,8},{5,9},{6,10},{7,11},{8,12}};
- HashTable H;
- int i,p,j;
- KeyType k;
- H.Init_HashTable();
- for(i=0;i<11;i++) //插入前11个记录
- {
- j=H.Insert_Hash(r[i]);
- if(j==-1)
- cout<<"表中已有关键字为"<<r[i].key<<" "<<r[i].ord<<"的记录"<<endl;
- }
- cout<<"按哈希地址顺序遍历哈希表"<<endl;
- H.Traverse_HashTable();
- cout<<endl;
- cout<<"输入要查找的记录的关键字:";
- cin>>k;
- j=H.Search_Hash(k,p);
- if(j==1)
- H.Get_Data(p);
- else
- cout<<"无此记录"<<endl;
- j=H.Insert_Hash(r[11]); //插入最后一个元素
- if(j==0)
- {
- cout<<"插入失败"<<endl;
- cout<<"需要重建哈希表才可以插入"<<endl;
- cout<<"____重建哈希表____"<<endl;
- H.Insert_Hash(r[i]); //重建后重新插入
- }
- cout<<"遍历重建后的哈希表"<<endl;
- H.Traverse_HashTable();
- cout<<endl;
- cout<<"输入要查找的记录的关键字:";
- cin>>k;
- j=H.Search_Hash(k,p);
- if(j==1)
- H.Get_Data(p);
- else
- cout<<"该记录不存在"<<endl;
- cout<<"____销毁哈希表____"<<endl;
- H.Destroy_HashTable();
- return 0;
- }
测试结果:
- 按哈希地址顺序遍历哈希表
- 哈希地址0->10
- 元素的关键字值和它的标志分别是:5 9
- 元素的关键字值和它的标志分别是:1 5
- 元素的关键字值和它的标志分别是:2 6
- 元素的关键字值和它的标志分别是:3 7
- 元素的关键字值和它的标志分别是:4 8
- 元素的关键字值和它的标志分别是:60 2
- 元素的关键字值和它的标志分别是:17 1
- 元素的关键字值和它的标志分别是:29 3
- 元素的关键字值和它的标志分别是:38 4
- 元素的关键字值和它的标志分别是:6 10
- 元素的关键字值和它的标志分别是:7 11
- 输入要查找的记录的关键字:5
- 元素的关键字值和它的标志分别是:5 9
- ____重建hash表_____
- 插入失败
- 需要重建哈希表才可以插入
- ____重建哈希表____
- 遍历重建后的哈希表
- 哈希地址0->18
- 元素的关键字值和它的标志分别是:38 4
- 元素的关键字值和它的标志分别是:1 5
- 元素的关键字值和它的标志分别是:2 6
- 元素的关键字值和它的标志分别是:3 7
- 元素的关键字值和它的标志分别是:4 8
- 元素的关键字值和它的标志分别是:5 9
- 元素的关键字值和它的标志分别是:60 2
- 元素的关键字值和它的标志分别是:6 10
- 元素的关键字值和它的标志分别是:7 11
- 元素的关键字值和它的标志分别是:8 12
- 元素的关键字值和它的标志分别是:29 3
- 元素的关键字值和它的标志分别是:17 1
- 输入要查找的记录的关键字:7
- 元素的关键字值和它的标志分别是:7 11
- ____销毁哈希表____
- Press any key to continue
哈希表的C++实现(转)的更多相关文章
- [PHP内核探索]PHP中的哈希表
在PHP内核中,其中一个很重要的数据结构就是HashTable.我们常用的数组,在内核中就是用HashTable来实现.那么,PHP的HashTable是怎么实现的呢?最近在看HashTable的数据 ...
- Java 哈希表运用-LeetCode 1 Two Sum
Given an array of integers, find two numbers such that they add up to a specific target number. The ...
- ELF Format 笔记(十五)—— 符号哈希表
ilocker:关注 Android 安全(新手) QQ: 2597294287 符号哈希表用于支援符号表的访问,能够提高符号搜索速度. 下表用于解释该哈希表的组织,但该格式并不属于 ELF 规范. ...
- Java基础知识笔记(一:修饰词、向量、哈希表)
一.Java语言的特点(养成经常查看Java在线帮助文档的习惯) (1)简单性:Java语言是在C和C++计算机语言的基础上进行简化和改进的一种新型计算机语言.它去掉了C和C++最难正确应用的指针和最 ...
- 什么叫哈希表(Hash Table)
散列表(也叫哈希表),是根据关键码值直接进行访问的数据结构,也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数,存放记录的数组叫做散列表. - 数据结构 ...
- 【哈希表】CodeVs1230元素查找
一.写在前面 哈希表(Hash Table),又称散列表,是一种可以快速处理插入和查询操作的数据结构.哈希表体现着函数映射的思想,它将数据与其存储位置通过某种函数联系起来,其在查询时的高效性也体现在这 ...
- openssl lhash 数据结构哈希表
哈希表是一种数据结构,通过在记录的存储位置和它的关键字之间建立确定的对应关系,来快速查询表中的数据: openssl lhash.h 为我们提供了哈希表OPENSSL_LHASH 的相关接口,我们可以 ...
- Berkeley DB的数据存储结构——哈希表(Hash Table)、B树(BTree)、队列(Queue)、记录号(Recno)
Berkeley DB的数据存储结构 BDB支持四种数据存储结构及相应算法,官方称为访问方法(Access Method),分别是哈希表(Hash Table).B树(BTree).队列(Queue) ...
- python数据结构与算法——哈希表
哈希表 学习笔记 参考翻译自:<复杂性思考> 及对应的online版本:http://greenteapress.com/complexity/html/thinkcomplexity00 ...
- [转]:Delphi 中的哈希表(1): THashedStringList
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...
随机推荐
- android Camera 数据流程分析
这篇文章主要针对其数据流程进行分析.Camera一般用于图像浏览.拍照和视频录制.这里先对图像浏览和拍照的数据流进行分析,后面再对视频电话部分进行分析. 1.针对HAL层对摄像头数据处理补充一下 Li ...
- Android常用代码集合
这篇文章主要记录一些常用的一些代码段,方便以后查阅,不断更新中. 1:调用浏览器,载入某网址 1 2 3 Uri uri = Uri.parse("http://www.android-st ...
- yii2 model源码解读
模型yii\base\Model 模型主要实现了验证规则和验证器确保输入的数据是安全和正确的. 模型的流程: 1.从请求中读取数据.使用load或者loadMultiple或者手动赋值.load会根据 ...
- ActionScript 3 中的强制类型转换
以前AS中是这样进行强制类型转换的:假设有一个类叫做Class1,我们声明了一个它的对象 c1,如果想要将它转换成Class2类型,只要这样写: Class2(c1); 在AS3中你依然可以这样写,但 ...
- Playing with ptrace, Part I
X86_64 的 Redhat / Centos / Scientific 下面,若要编译.运行32位程序,需要安装以下包: yum install libgcc.i686 yum install g ...
- LeetCode: Palindrome Partition
LeetCode: Palindrome Partition Given a string s, partition s such that every substring of the partit ...
- MySQL查询优化 (一)
以下的文章主要讲述的是MySQL查询优化的5个十分好用方法,熟悉SQL语句的人都清楚,如果要对一个任务进行操作的话,SQL语句可以有很多种相关写法,但是不同的写法查询的性能可能会有天壤之别. 本文列举 ...
- Opacity多浏览器透明度兼容处理(转)
用来设定元素透明度的 Opacity 是CSS 3里的一个属性.当然现在还只有少部分浏览器支持. 不过各个浏览器都有自己的私有属性来支持,其中包括老版本的Mozilla和Safari: IE: fil ...
- iOS如何随意的穿插跳跃,push来pop去
iOS如何随意的穿插跳跃,push来pop去? 主题思想:如A.B.C.D 四个视图控制器. 想要在 A push B 后, B 在push 到 D ,然后从 D pop 到 C ,在从 C pop ...
- iOS-实现验证码倒计时功能(1)
验证码倒计时按钮的应用是非常普遍的,该Blog就和你一起来写一个IDCountDownButton来实现验证码倒计时的效果.你可以想使用普通的UIButton类型按钮一样,只需要设置其倒计时时长(若未 ...