数据结构: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相关推荐

  1. 散列表(Hash Table)

    散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列 ...

  2. PHP关联数组和哈希表(hash table) 未指定

    PHP有数据的一个非常重要的一类,就是关联数组.又称为哈希表(hash table),是一种很好用的数据结构. 在程序中.我们可能会遇到须要消重的问题,举一个最简单的模型: 有一份username列表 ...

  3. 数据结构基础-Hash Table详解

    理解Hash 哈希表(hash table)是从一个集合A到另一个集合B的映射(mapping). 映射是一种对应关系,而且集合A的某个元素只能对应集合B中的一个元素.但反过来,集合B中的一个元素可能 ...

  4. linux c glib中的hash table

    Glib是一个C语言编写的库,它本身是Gnome的一个部分,后来Glib剥离出来,它为Gnome提供了一些操作字符串和常用数据结构的工具函数.这些好的工具函数既然可以提供给gnome,使用,自然也可以 ...

  5. Berkeley DB的数据存储结构——哈希表(Hash Table)、B树(BTree)、队列(Queue)、记录号(Recno)...

    Berkeley DB的数据存储结构 BDB支持四种数据存储结构及相应算法,官方称为访问方法(Access Method),分别是哈希表(Hash Table).B树(BTree).队列(Queue) ...

  6. 纸上谈兵: 哈希表 (hash table)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! HASH 哈希表(hash table)是从一个集合A到另一个集合B的映射(map ...

  7. 十、散列表(Hash Table)

    一.概述 散列表(Hash Table),也称"哈希表"或者"Hash 表" 1.相关概念 原始数据叫作键(键值)或关键字(key): 将原始数据转化为数组下标 ...

  8. [C++]怎么样实现一个较快的Hash Table

    我们服务器一直在用boost/sgl stl的hash table,但是从来没有考虑过其中的效率问题,虽然hash_map/unordered_map跑的可能真的比map快一些,可能应该不是你理解的那 ...

  9. 数据结构学习笔记(七):哈希表(Hash Table)

    目录 1 哈希表的含义与结构特点 1.1 哈希(Hash)即无序 1.2 从数组看哈希表的结构特点 2 哈希函数(Hash Function)与哈希冲突(Hash Collision) 2.1 哈希函 ...

  10. C++利用二次探查实现存储机制hash table的算法(附完整源码)

    C++利用二次探查实现存储机制hash table的算法 C++利用二次探查实现存储机制hash table的算法完整源码(定义,实现,main函数测试) C++利用二次探查实现存储机制hash ta ...

最新文章

  1. SAP QM-IDI 初探
  2. 错误:无法作为数据库主体执行,因为主体 dbo 不存在、无法模拟这种类型的主体,或您没有所需的权限...
  3. 产品运营必须知道的几个概念,什么是用户群体?
  4. pom文件内标签的讲解
  5. 石油化工静设备计算机辅助设计桌面系统,PV Desktop 石油化工静设备计算机辅助设计桌面系统简介...
  6. go int64转string_go常见问题收录
  7. 【C++深入探索】Copy-and-swap idiom详解和实现安全自我赋值
  8. 搭建DNS域名解析服务器
  9. 收藏:如何实现路由器的本地验证和授权
  10. pandas数据处理实践二(排序(sort_index()、sort_values())、连接(Concatenate(连接,串联)和Combine(结合、联合))
  11. 小程序定制开发和模板软件的区别和优势
  12. catia里画铰链_基于CATIA的汽车车门铰链设计
  13. 计算机与打印机脱机后怎么共享,打印机脱机工作怎么恢复(连接的共享打印机脱机)...
  14. Python with as用法详解
  15. HDS存储产品概述1
  16. 用html计算长方形的面积公式,【长方形正方形的面积计算公式】《长方形、正方形的面积计算》优秀教学反思...
  17. c# 通过手淘分享查询淘宝优惠券
  18. 硬盘主分区和逻辑驱动器的区别
  19. 南开大学计算机学院李越,李越 简历 - 名人简历
  20. 5G室内小型基站行业现状调研及趋势分析报告

热门文章

  1. Python实现undo操作
  2. 若要赞美晴天 请等到黄昏之后
  3. 计算机毕业设计(70)php小程序毕设作品之干洗店洗衣小程序系统
  4. 基于java的人力资源管理系统_基于JavaWeb的企业人力资源管理系统的设计与实现...
  5. 自己动手做一款蓝牙小车
  6. 泉州集训之HSY的day1
  7. Confluence备份恢复报错: AO_187CCC_SIDEBAR_LINK
  8. 三电极体系电化学测量模组
  9. 有源晶振和无源晶振的比较
  10. 烂泥行天下 php,烂泥:php5.6源码安装及php-fpm配置与nginx集成