数据结构之链式哈希表

## 数据结构之链式哈希表
哈希表(Hash table,散列表),由多组键-值组成一张查询表,通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。
哈希表中元素是由哈希函数确定的。将数据元素的关键字K作为自变量,通过一定的函数关系(称为哈希函数),计算出的值,即为该元素的存储地址。表示为:Addr = H(key)。

哈希函数特点:
(1)输入任意性:函数的输入可以是任意大小的数据;
(2)输出固定性:函数的输出是一个固定大小的数据;
(3)防碰撞特性
(4)单向性
(5)计算hash值的速度比较快
注:其中防碰撞特性要求哈希函数输出的值是均匀分布,并且尽量避免冲突。

哈希表的特点:
1、集合数组与链表的特性于一身,基于数组,实现快速查找,链表解决冲突问题。
2、它提供了快速的查找操作、理想情况下(没有冲突的情况),时间复杂度为·O(1),在海量数据的筛选方面应用比较广泛。

哈希表处理冲突方式:
1、链地址法
指把所有的冲突关键字存储在一个线性链表中,这个链表由其散列地址唯一标识。
2、开放定址法
开放地址法通常需要有三种方法:线性探测、二次探测、再哈希法。

代码实现:
以下为链式哈希表的增删查改部分代码

#include<stdio.h>
#include<string.h>
#include<strings.h>
#include <stdlib.h>
#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中也用到哈希表保存变量,等等方面。哈希表在查找效率方面相对于数组、链表会更好一点。

猜你喜欢

转载自blog.csdn.net/weixin_40732273/article/details/107796087