Hash Table
数据结构:hash_map原理
这是一节让你深入理解hash_map的介绍,如果你只是想囫囵吞枣,不想理解其原理,你倒是可以略过这一节,但我还是建议你看看,多了解一些没有坏处。
hash_map基于hash table(哈希表)。哈希表最大的优点,就是把数据的存储和查找消耗的时间大大降低,几乎可以看成是常数时间;而代价仅仅是消耗比较多的内存。然而在当前可利用内存越来越多的情况下,用空间换时间的做法是值得的。另外,编码比较容易也是它的特点之一。
其基本原理是:使用一个下标范围比较大的数组来存储元素。可以设计一个函数(哈希函数,也叫做散列函数),使得每个元素的关键字都与一个函数值(即数组下标,hash值)相对应,于是用这个数组单元来存储这个元素;也可以简单的理解为,按照关键字为每一个元素“分类”,然后将这个元素存储在相应“类”所对应的地方,称为桶。
但是,不能够保证每个元素的关键字与函数值是一一对应的,因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了“冲突”,换句话说,就是把不同的元素分在了相同的“类”之中。 总的来说,“直接定址”与“解决冲突”是哈希表的两大特点。
hash_map,首先分配一大片内存,形成许多桶。是利用hash函数,对key进行映射到不同区域(桶)进行保存。
其插入过程是:
1. 得到key
2. 通过hash函数得到hash值
3. 得到桶号(一般都为hash值对桶数求模)
4. 存放key和value在桶内。
其取值过程是:
1. 得到key
2. 通过hash函数得到hash值
3. 得到桶号(一般都为hash值对桶数求模)
4. 比较桶的内部元素是否与key相等,若都不相等,则没有找到。
5. 取出相等的记录的value。
hash_map中直接地址用hash函数生成,解决冲突,用比较函数解决。这里可以看出,如果每个桶内部只有一个元素,那么查找的时候只有一次比较。当许多桶内没有值时,许多查询就会更快了(指查不到的时候).
由此可见,要实现哈希表, 和用户相关的是:hash函数和比较函数。这两个参数刚好是我们在使用hash_map时需要指定的参数。
来源: http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailHashMap
一个实现
/**PROGRAM :哈希表的综合操作 **/
/**CONTENT :Insert,Search,Deltet **/
/* * * * * * * * * * * * * * * * * * * * * * * **/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 30 /*哈希表的最大容量,与所采用的哈希函数有关*/
typedef enum{False,True} BOOL;
typedef enum{NULLKEY,HAVEKEY,DELKEY} HAVEORNOT;
/*哈希表元素的三种状态,没有记录、有记录、有过记录但已被删除*/
typedef struct /*定义哈希表的结构*/
{
int elem[MAXSIZE]; /* 数据元素体 */
HAVEORNOT elemflag[MAXSIZE]; /*元素状态标志,没有记录、有记录、有过记录但已被删除*/
int count; /*哈希表中当前元素的个数 */
}HashTable;
typedef struct
{int keynum; /*记录的数据域,只有关键字一项*/
}Record;
void InitialHash(HashTable*); /*初始化哈希表*/
void CreateHash(HashTable*);/* 根据从键盘上输入的一系列整数建立哈希表 */
void PrintHash(HashTable); /*显示哈希表中的所有元素*/
BOOL SearchHash(HashTable,int,int*); /*在哈希表中查找元素*/
BOOL InsertHash(HashTable*,Record); /*在哈希表中插入元素*/
BOOL DeleteHash(HashTable*,Record); /*在哈希表中删除元素*/
int Hash(int); /*哈希函数*/
void main()
{
HashTable H; /*声明哈希表H*/
char ch,j='y';
int position;
Record R;
BOOL temp;
//textbackground(3); /*设定屏幕颜色*/
//textcolor(15);
//clrscr();
InitialHash(&H);
CreateHash(&H);
/*-------------------------程序说明-------------------------------*/
printf("This program will show how to operate to a HashTable./n");
printf("You can display all elems,search a elem,/ninsert a elem,delete a elem./n");
/*----------------------------------------------------------------*/
while(j!='n')
{
printf("1.display/n");
printf("2.search/n");
printf("3.insert/n");
printf("4.delete/n");
printf("5.exit/n");
scanf(" %c",&ch); /*输入操作选项*/
switch(ch)
{
case '1':if(H.count) PrintHash(H); /*哈希表不空*/
else printf("The HashTable has no elem!/n");
break;
case '2':if(!H.count) printf("The HashTable has no elem!/n"); /*哈希表空*/
else
{printf("Please input the keynum(int) of the elem to search:");
scanf("%d",&R.keynum); /*输入待查记录的关键字*/
temp=SearchHash(H,R.keynum,&position);
/*temp=True:记录查找成功;temp=False:没有找到待查记录*/
if(temp) printf("The position of the elem is %d/n",position);
else printf("The elem isn't exist!/n");
}
break;
case '3':if(H.count==MAXSIZE) /*哈希表已满*/
{printf("The HashTable is full!/n");
break;
}
printf("Please input the elem(int) to insert:");
scanf("%d",&R.keynum); /*输入要插入的记录*/
temp=InsertHash(&H,R);
/*temp=True:记录插入成功;temp=False:已存在关键字相同的记录*/
if(temp) printf("Sucess to insert the elem!/n");
else printf("Fail to insert the elem.The same elem has been exist!/n");
break;
case '4':printf("Please input the keynum of the elem(int) to delet:");
scanf("%d",&R.keynum); /*输入要删除记录的关键字*/
temp=DeleteHash(&H,R);
/*temp=True:记录删除成功;temp=False:待删记录不存在 */
if(temp) printf("Sucess to delete the elem!/n");
else printf("The elem isn't exist in the HashTable!/n");
break;
default: j='n';
}
}
printf("The program is over!/nPress any key to shut off the window!/n");
getchar();
}
void InitialHash(HashTable *H)
{/*哈希表初始化*/
int i;
(*H).count=0;
for(i=0;i<MAXSIZE;i++) (*H).elemflag[i]=NULLKEY;
}
void CreateHash(HashTable *H)
{/* 根据从键盘上输入的一系列整数(不超过12个,以-1结束)建立哈希表 */
Record e;
printf("请输入的一系列整数(不超过12个,以-1结束)以建立哈希表:/n");
scanf("%d",&e.keynum);
while(e.keynum!=-1)
if(InsertHash(H,e)) scanf("%d",&e.keynum);
else
{printf("请输入不重复的数据!");
return;
}
}
void PrintHash(HashTable H)
{ /*显示哈希表所有元素及其所在位置*/
int i;
for(i=0;i<MAXSIZE;i++) /*显示哈希表中记录所在位置*/
if(H.elemflag[i]==HAVEKEY) /*只显示标志为HAVEKEY(存放有记录)的元素*/
printf("%-4d",i);
printf("/n");
for(i=0;i<MAXSIZE;i++) /*显示哈希表中记录值*/
if(H.elemflag[i]==HAVEKEY)
printf("%-4d",H.elem[i]);
printf("/ncount:%d/n",H.count); /*显示哈希表当前记录数*/
}
BOOL SearchHash(HashTable H,int k,int *p)
{/*在开放定址哈希表H中查找关键字为k的数据元素,若查找成功,以p指示
待查数据元素在表中的位置,并返回True;否则,以p指示插入位置,并
返回False*/
int p1;
p1=(*p)=Hash(k); /*求得哈希地址*/
while(H.elemflag[(*p)]==HAVEKEY&&k!=H.elem[(*p)])
/*该位置中填有记录并且关键字不相等*/
{
(*p)++; /*冲突处理方法:线性探测再散列*/
if((*p)>=MAXSIZE) (*p)=(*p)%MAXSIZE; /*循环搜索*/
if((*p)==p1) return False; /*整个表已搜索完,没有找到待查元素*/
}
if(k==H.elem[(*p)]&&H.elemflag[(*p)]==HAVEKEY) /*查找成功,p指示待查元素位置*/
return True;
else return False; /*查找不成功*/
}
BOOL InsertHash(HashTable *H,Record e)
{/*查找不成功时插入元素e到开放定址哈希表H中,并返回True,否则返回False*/
int p;
if(SearchHash((*H),e.keynum,&p)) /*表中已有与e有相同关键字的元素*/
return False;
else
{(*H).elemflag[p]=HAVEKEY; /*设置标志为HAVEKEY,表示该位置已有记录*/
(*H).elem[p]=e.keynum; /*插入记录*/
(*H).count++; /*哈希表当前长度加一 */
return True;
}
}
BOOL DeleteHash(HashTable *H,Record e)
{/*在查找成功时删除待删元素e,并返回True,否则返回False*/
int p;
if(!SearchHash((*H),e.keynum,&p)) /*表中不存在待删元素*/
return False;
else
{(*H).elemflag[p]=DELKEY; /*设置标志为DELKEY,表明该元素已被删除*/
(*H).count--; /*哈希表当前长度减一*/
return True;
}
}
int Hash(int kn)
{/*哈希函数:H(key)=key MOD 11*/
return (kn%11);
}
//code2:
///
哈希表的设计主要是设计哈希函数 哈希函数:将关键字映射到哈希表的位置 哈希函数的建立有五种常见方法: 1. 除余法 2.折叠法 3.平方取中法 4.提取法 5. 基数转换法 哈希冲突解决方法 1. 开放定址法 开放定址法又分为线性探查法,二次探查法,双散列函数探查法 2.再哈希法 3.链地址法 4.建立一个公共溢出区 可扩展文件的散列函数 1.可扩展散列 2.线性散列哈希程序示例: 冲突解决方法为:双散列函数探查法 哈希函数关键字为:人名字母ASCII相加 哈希函数为:关键字%M,从而映射到哈希表中的位置 代码:#include<stdio.h> #include<conio.h> #define HASH_LEN 50 //哈希表的长度 #define M 47 //随机数 #define NAME_NO 30 //人名的个数 typedef struct { char *py; //名字的拼音 int k; //拼音所对应的整数 }NAME; NAME NameList[HASH_LEN]; //全局变量NAME typedef struct //哈希表 { char *py; //名字的拼音 int k; //拼音所对应的整数 int si; //查找长度 }HASH; HASH HashList[HASH_LEN]; //全局变量HASH void InitNameList() //姓名(结构体数组)初始化 { char *f; int r,s0,i; NameList[0].py="wanghui"; NameList[1].py="mayuelong"; NameList[2].py="chenzhicheng"; NameList[3].py="sunpeng"; NameList[4].py="zengqinghui"; NameList[5].py="liqingbo"; NameList[6].py="liujunpeng"; NameList[7].py="jiangquanlei"; NameList[8].py="xingzhengchuan"; NameList[9].py="luzhaoqian"; NameList[10].py="gaowenhu"; NameList[11].py="zhuhaoyin"; NameList[12].py="chenlili"; NameList[13].py="wuyunyun"; NameList[14].py="huangjuanxia"; NameList[15].py="wangyan"; NameList[16].py="zhoutao"; NameList[17].py="jiangzhenyu"; NameList[18].py="liuxiaolong"; NameList[19].py="wangziming"; NameList[20].py="fengjunbo"; NameList[21].py="lilei"; NameList[22].py="wangjia"; NameList[23].py="zhangjianguo"; NameList[24].py="zhuqingqing"; NameList[25].py="huangmin"; NameList[26].py="haoyuhan"; NameList[27].py="zhoutao"; NameList[28].py="zhujiang"; NameList[29].py="lixiaojun"; for (i=0;i<NAME_NO;i++) {s0=0;f=NameList[i].py; for (r=0;*(f+r)!='\0';r++)s0=*(f+r)+s0; NameList[i].k=s0; } } void CreateHashList() //建立哈希表 {int i;for (i=0; i<HASH_LEN;i++){HashList[i].py="";HashList[i].k=0;HashList[i].si=0;} for (i=0;i<HASH_LEN;i++){int sum=0;int adr=(NameList[i].k)%M; //哈希函数int d=adr;if(HashList[adr].si==0) //如果不冲突{HashList[adr].k=NameList[i].k;HashList[adr].py=NameList[i].py;HashList[adr].si=1;}else //冲突{do{d=(d+NameList[i].k%10+1)%M; //伪随机探测再散列法处理冲突 sum=sum+1; //查找次数加1 }while (HashList[d].k!=0);HashList[d].k=NameList[i].k;HashList[d].py=NameList[i].py;HashList[d].si=sum+1;}}} void FindList() //查找 {char name[20]={0};int s0=0,r,sum=1,adr,d; printf("\n请输入姓名的拼音:"); scanf("%s",name); for (r=0;r<20;r++) //求出姓名的拼音所对应的整数(关键字)s0+=name[r]; adr=s0%M; //使用哈希函数 d=adr; if(HashList[adr].k==s0) //分3种情况进行判断printf("\n姓名:%s 关键字:%d 查找长度为: 1",HashList[d].py,s0); else if (HashList[adr].k==0)printf("无此记录!"); else {int g=0;do{d=(d+s0%10+1)%M; //伪随机探测再散列法处理冲突 sum=sum+1;if (HashList[d].k==0){printf("无此记录! ");g=1; }if (HashList[d].k==s0){ printf("\n姓名:%s 关键字:%d 查找长度为:%d",HashList[d].py,s0,sum);g=1;}}while(g==0); } } void Display() // 显示哈希表 {int i; float average=0;printf("\n\n地址\t关键字\t\t搜索长度\tH(key)\t 姓名\n"); //显示的格式for(i=0; i<50; i++) {printf("%d ",i);printf("\t%d ",HashList[i].k);printf("\t\t%d ",HashList[i].si);printf("\t\t%d ",HashList[i].k%M);printf("\t %s ",HashList[i].py);printf("\n"); } for (i=0;i<HASH_LEN;i++) average+=HashList[i].si; average/=NAME_NO; printf("\n\n平均查找长度:ASL(%d)=%f \n\n",NAME_NO,average); }void main() {char ch1; printf("\n 哈希表的建立和查找\n");printf(" *-------------------------------------------*\n");printf(" | D. 显示哈希表 |\n");printf(" | F. 查找 |\n");printf(" | Q. 退出 |\n");printf(" *-------------------------------------------*\n");InitNameList(); CreateHashList (); while(1) { printf("\n Option-:"); fflush(stdin);ch1=getchar();if (ch1=='D'||ch1=='d')Display(); else if (ch1=='F'||ch1=='f')FindList();else if (ch1=='Q'||ch1=='q')return;else{printf("\n请输入正确的选择!");}}}程序示例2: #include <math.h> #include <stdio.h> #include <stdlib.h> #define MAXSIZE 30 typedef enum{False,True} BOOL; typedef enum{NULLKEY,HAVEKEY,DELKEY} HAVEORNOT;typedef struct { int elem[MAXSIZE]; HAVEORNOT elemflag[MAXSIZE]; int count; }HashTable; typedef struct {int keynum; }Record; void InitialHash(HashTable*); void CreateHash(HashTable*); void PrintHash(HashTable); BOOL SearchHash(HashTable,int,int*); BOOL InsertHash(HashTable*,Record); BOOL DeleteHash(HashTable*,Record); int Hash(int);void main() {HashTable H;char ch,j='y';int position;Record R;BOOL temp;//textbackground(3);//textcolor(15);//clrscr();InitialHash(&H);CreateHash(&H);printf("This program will show how to operate to a HashTable.\n");printf("You can display all elems,search a elem,\ninsert a elem,delete a elem.\n");while(j!='n'){printf("1.display\n");printf("2.search\n");printf("3.insert\n");printf("4.delete\n");printf("5.exit\n");scanf(" %c",&ch);switch(ch){case '1':if(H.count) PrintHash(H);else printf("The HashTable has no elem!\n");break;case '2':if(!H.count) printf("The HashTable has no elem!\n");else{printf("Please input the keynum(int) of the elem to search:");scanf("%d",&R.keynum);temp=SearchHash(H,R.keynum,&position);if(temp) printf("The position of the elem is %d\n",position);else printf("The elem isn't exist!\n");}break;case '3':if(H.count==MAXSIZE){printf("The HashTable is full!\n");break;}printf("Please input the elem(int) to insert:");scanf("%d",&R.keynum);temp=InsertHash(&H,R);if(temp) printf("Sucess to insert the elem!\n");else printf("Fail to insert the elem.The same elem has been exist!\n");break;case '4':printf("Please input the keynum of the elem(int) to delet:");scanf("%d",&R.keynum);temp=DeleteHash(&H,R);if(temp) printf("Sucess to delete the elem!\n");else printf("The elem isn't exist in the HashTable!\n");break;default: j='n';}}printf("The program is over!\nPress any key to shut off the window!\n");getchar(); }void InitialHash(HashTable *H) {int i;(*H).count=0;for(i=0;i<MAXSIZE;i++) (*H).elemflag[i]=NULLKEY; }void CreateHash(HashTable *H) { Record e; printf("请输入的一系列整数(不超过12个,以-1结束)以建立哈希表:\n"); scanf("%d",&e.keynum); while(e.keynum!=-1)if(InsertHash(H,e))scanf("%d",&e.keynum);else{printf("请输入不重复的数据!");return;} }void PrintHash(HashTable H) { int i;for(i=0;i<MAXSIZE;i++)if(H.elemflag[i]==HAVEKEY)printf("%-4d",i);printf("\n");for(i=0;i<MAXSIZE;i++)if(H.elemflag[i]==HAVEKEY)printf("%-4d",H.elem[i]);printf("\ncount:%d\n",H.count); }BOOL SearchHash(HashTable H,int k,int *p) {int p1;p1=(*p)=Hash(k);while(H.elemflag[(*p)]==HAVEKEY&&k!=H.elem[(*p)]){(*p)++;if((*p)>=MAXSIZE) (*p)=(*p)%MAXSIZE;if((*p)==p1) return False;}if(k==H.elem[(*p)]&&H.elemflag[(*p)]==HAVEKEY)return True;else return False; }BOOL InsertHash(HashTable *H,Record e) {int p;if(SearchHash((*H),e.keynum,&p))return False;else{(*H).elemflag[p]=HAVEKEY;(*H).elem[p]=e.keynum;(*H).count++;return True;} }BOOL DeleteHash(HashTable *H,Record e) {int p;if(!SearchHash((*H),e.keynum,&p))return False;else{(*H).elemflag[p]=DELKEY;(*H).count--;return True;} }int Hash(int kn) {return (kn%11); }
总结
以上是生活随笔为你收集整理的Hash Table的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 北航 2018计算机学院排课,关于201
- 下一篇: 使用注册表编辑win10鼠标右键菜单,详