## 数据结构之链式哈希表
哈希表(Hash table,散列表),由多组键-值组成一张查询表,通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。
哈希表中元素是由哈希函数确定的。将数据元素的关键字K作为自变量,通过一定的函数关系(称为哈希函数),计算出的值,即为该元素的存储地址。表示为:Addr = H(key)。
哈希函数特点:
(1)输入任意性:函数的输入可以是任意大小的数据;
(2)输出固定性:函数的输出是一个固定大小的数据;
(3)防碰撞特性
(4)单向性
(5)计算hash值的速度比较快
注:其中防碰撞特性要求哈希函数输出的值是均匀分布,并且尽量避免冲突。
哈希表的特点:
1、集合数组与链表的特性于一身,基于数组,实现快速查找,链表解决冲突问题。
2、它提供了快速的查找操作、理想情况下(没有冲突的情况),时间复杂度为·O(1),在海量数据的筛选方面应用比较广泛。
哈希表处理冲突方式:
1、链地址法
指把所有的冲突关键字存储在一个线性链表中,这个链表由其散列地址唯一标识。
2、开放定址法
开放地址法通常需要有三种方法:线性探测、二次探测、再哈希法。
代码实现:
以下为链式哈希表的增删查改部分代码
#include
#include
#include
#include
#define BITSPERBYTE ((int) (8 * sizeof(char)))
#define BITS(type) ((int) (BITSPERBYTE * (int) sizeof(type)))
//哈希节点
struct hash
{
struct hash *form;
char *key;
char *val;
};
//哈希表
struct HashTable
{
struct hash **hash_table;
int bucket;//桶数
}*HashTable;
//哈希函数
static int hashIndex(char *name,int bucket)
{
unsigned int sum;
int i;
/*
Add in each character shifted up progressively by 7 bits. The shift amount is rounded so as to not shift too
far. It thus cycles with each new cycle placing character shifted up by one bit.
*/
i = 0;
sum = 0;
while (*name) {
sum += (((int) *name++) << i);
i = (i + 7) % (BITS(int) - BITSPERBYTE);
}
return sum%bucket;
}
//哈希表创建
struct HashTable *hash_create(int size)
{
struct HashTable *temp;
temp = (struct HashTable *)malloc(sizeof(struct HashTable));
if(temp == NULL)
{
printf("malloc HashTable fail\n");
return NULL;
}
temp->bucket = size;
if((temp->hash_table = (struct hash **)malloc(size * sizeof(struct hash *))) == NULL)
{
printf("malloc hash_table fail\n");
free(temp);
return NULL;
}
memset(temp->hash_table , 0 , size * sizeof(struct hash *));
return temp;
}
char *sclone(char *strval)
{
if(strval ==NULL)
{
printf("sclone argc invalib!\n");
}
char *tmp = NULL;
tmp = (char *)malloc(strlen(strval)+1);
if(tmp==NULL)
{
printf("sclone malloc fail!\n");
return NULL;
}
strcpy(tmp,strval);
return tmp;
}
//哈希表插入
struct hash *hashenter(struct HashTable *tp,char *name,char *value)
{
int index=0;
struct hash *sp=NULL,*sp_form = NULL;
index = hashIndex(name , tp->bucket);
if((sp = tp->hash_table[index]) != NULL)
{
while(sp!=NULL)
{
if(strcmp(name,sp->key)==0)
break;
sp_form = sp;
sp = sp->form;
}
if(sp)
{
sp->key=sclone(name);
sp->val=sclone(value);
}
else
{
sp=(struct hash *)malloc(sizeof(struct hash));
if(sp ==NULL)
{
printf("malloc hash_table fail!\n");
}
sp->key=sclone(name);
sp->val=sclone(value);
sp_form->form = sp;
sp->form = NULL;
}
}
else
{
sp=(struct hash *)malloc(sizeof(struct hash));
if(sp ==NULL)
{
printf("malloc hash fail!\n");
return NULL;
}
tp->hash_table[index] = sp;
sp->key=sclone(name);
sp->val=sclone(value);
sp->form = NULL;
}
return sp;
}
//哈希表查询
struct hash *hashLookup(struct HashTable *tp,char *name)
{
struct hash *sp=NULL;
sp=tp->hash_table[hashIndex(name , tp->bucket)];
while(sp!=NULL)
{
if(strcmp(name,sp->key)==0)
{
return sp;
}
sp=sp->form;
}
return NULL;
}
//哈希表删除
int hashDelete(struct HashTable *tp,char *name)
{
struct hash *sp = NULL;
struct hash *sp_form = NULL;
sp=tp->hash_table[hashIndex(name , tp->bucket)];
while(sp != NULL)
{
if(strcmp(name,sp->key)==0)
break;
sp_form=sp;
sp=sp->form;
}
if(sp == NULL)
{
printf("name invalib!\n");
return -1;
}
if(sp_form ==NULL)
{
tp->hash_table[hashIndex(name , tp->bucket)] = sp->form;
}
else
{
sp_form->form=sp->form;
}
free(sp->key);
free(sp->val);
free(sp);
return 0;
}
//获取数据
char *getvar(struct HashTable *tp,char *name)
{
struct hash *sp = NULL;
if((sp = hashLookup(tp,name)) == NULL)
{
printf(" hashLookup NULL!\n");
return NULL;
}
return sp->val;
}
//插入数据
char *setvar(struct HashTable *tp,char *name,char *value)
{
struct hash *sp=NULL;
if((sp=hashenter(tp,name,value)) == NULL)
{
return NULL;
}
return sp->val;
}
int print_mess()
{
printf("--------------------------------------\n");
printf("1:add---------------------------------\n");
printf("2:delete------------------------------\n");
printf("3:printvar----------------------------\n");
printf("4:query-------------------------------\n");
printf("--------------------------------------\n");
}
void init(void)
{
HashTable = hash_create(20);
}
int add()
{
char name[25]={0};
char age[25]={0};
printf("please enter name:");
scanf("%s",name);
printf("please enter age:");
scanf("%s",age);
setvar(HashTable,name,age);
return 0;
}
int query()
{
char name[25]={0};
char *age =NULL;
printf("please enter name:");
scanf("%s",name);
if((age = getvar(HashTable,name)) != NULL)
printf("age:%s\n",age);
else
printf("query NULL!\n");
return 0;
}
int delete()
{
char name[25]={0};
printf("please enter name:");
scanf("%s",name);
if(hashDelete(HashTable,name) == -1)
printf("delete fail!\n");
else
printf("delete ok!\n");
return 0;
}
void printvar()
{
int i = 0;
struct hash *sp=NULL;
struct HashTable *tp = HashTable;
for(; i<tp->bucket ; i++)
{
if(sp = tp->hash_table[i])
{
while(sp != NULL)
{
printf("%s ",sp->key);
printf("%s\n",sp->val);
sp = sp->form;
}
}
}
}
int main(int argc,char **argv)
{
int mode;
init();
while(1)
{
print_mess();
while(1 != scanf("%d",&mode))
{
while(getchar() != '\n');
printf("\n please enter the mode:");
}
switch(mode)
{
case 1:
add();//增、改
break;
case 2:
delete();//删
break;
case 3:
printvar();//打印
break;
case 4:
query();//查
break;
default:
break;
}
}
return 0;
}
**总结:**哈希表应用比较广泛,比如uboot中环境变量的保存于设置、boa和goahead中也用到哈希表保存变量,等等方面。哈希表在查找效率方面相对于数组、链表会更好一点。