C语言实现哈希查找表相关操作

哈希查找表/散列表
	#include <stdio.h>
	#include <stdlib.h>
	#include "Base.h" 				// 09 查找
	
	/*全局变量*/
	int hashsize[] = {7,13,17,101,211,307,401,503,601,701,809,907,997};	//哈希表容量递增表,一个合适的素数序列 
	/*
	一般来说,不会将全局变量的定义写在头文件中,因为如果多个c源文件都添加了头文件,那很容易引起重定义的问题,这时候一般编译器都会提示。
	正确的作法是在c源文件中定义一个全局变量。在头文件中加入全局变量的声明。
	*/
	
	/* 宏定义 */
	#define DUPLICATE -1						//表中已存在关键字
	#define NULLKEY   -2						//标记此处无关键字 
	#define FULL      -3						//表已满(冲突次数达上限就认为表满) 
	#define EQ(a,b) ((a)==(b))
	#define Max 20								//查找表中元素个数
	
	/* 类型定义 */
	typedef struct								//开放定址哈希表存储表示
	{
		KeyType *elem;							//数据元素存储基址,动态分配数组 
		int count;								//当前哈希表包含的关键字个数 
		int sizeindex;							//hashsize[sizeindex]为当前容量 
	}HashTable; 
	
	/* (01)初始化一个空的哈希表 */
	void InitHash(HashTable *H)
	{
		(*H).count = 0;
		(*H).sizeindex = -1;
		(*H).elem = NULL;
	}
	
	/* (02)创建哈希表 */
	Status CreateHash(HashTable *H, Table T)
	{
		int i, tag;
		
		InitHash(H);
		
		RecreateHashTable(H);
		
		i=1;
		while(i<=T.length)				//将T中关键字依次插入到哈希表中
		{
			tag = InsertHash(H, T.elem[i].key);
			if(tag==SUCCESS)			//表中已有关键字或关键字顺利插入 
				i++;
			else						//重建哈希表后重新填充(冲突次数c已达冲突上限)
				i=1;
		}
		
		return OK;
	}
	
	/* (03)算法9.17:哈希表关键字搜索,p指向查找成功后的元素位置,*c记录发生冲突的次数 */
	/*
	在开放定址哈希表H中查找关键码为K的元素,若查找成功,以p指示待查数据,并返回DUPLICATE;
	若查找失败,以p指示插入位置,并返回NULLKEY;
	c用以计冲突次数,其初值置零,供建表插入时参考
	*/
	Status SearchHash(HashTable H, KeyType K, int *p)
	{
		int c, sup;
		
		c = 0;							//记录冲突次数 	
		sup = hashsize[H.sizeindex]/2;	//冲突上限(阈值可调)
		*p = fHash(H, K);				//p指向K应该插入的地址 	
	
		while(1)						
		{
			if(H.elem[*p]==NULLKEY)     //查找失败,表中未有此关键字
				return NULLKEY;			
			else if(EQ(H.elem[*p], K))  //查找成功,表中已有此关键字
				return DUPLICATE;		
			else if(++c==sup)			//冲突次数c已达冲突上限 (++c:先自增,后赋值)
				return FULL;
			else                        //该位置中填有记录并且关键字不相等(发生冲突)
				collision(H, p);		//重新定位p的地址 
		}
	}
	
	/* (04)算法9.18:哈希表关键字插入 */
	/*
	查找不成功时插入数据元素e到开放定址哈希表H中,并返回SUCCESS;
	若冲突次数过大,则重建哈希表,并返回UNSUCCESS;
	*/
	//重写了课本算法 
	Status InsertHash(HashTable *H, KeyType K)
	{
		int flag, p; 
	
		flag = SearchHash(*H, K, &p);
		
		if(flag==FULL)				//冲突次数c已达冲突上限(表已满)
		{
			RecreateHashTable(H);	//重建哈希表  
			return UNSUCCESS;
		}		
		else
		{
			if(flag==NULLKEY)       //查找失败,表中未有此关键字,可以进行插入(有冲突时已经解决了冲突)
			{
				H->elem[p] = K;		//插入K
				++(*H).count;
			}
			return SUCCESS; 
		}
	}
	
	/* (05)重建哈希表 */
	Status RecreateHashTable(HashTable *H)
	{
		int i, newv;
		
		(*H).count = 0;
		(*H).sizeindex++;
		newv = hashsize[(*H).sizeindex];
		 
		if((*H).elem!=NULL)
			free((*H).elem);
		
		//扩充了哈希表容量
		(*H).elem = (KeyType *)malloc(newv*sizeof(KeyType));
		if((*H).elem==NULL)
			return ERROR;
			
		for(i=0; i<newv; i++)
			(*H).elem[i] = NULLKEY;
		
		return OK;
	}
	
	/* (06)哈希函数 */
	/*
	除留余数法:H(key)= key % p,在此方法中,对于 p 的取值非常重要;
	由经验得知 p 可以为不大于 m 的质数或者不包含小于 20 的质因数的合数。
	*/
	int fHash(HashTable H, KeyType K)	//只是简单的取余 
	{	
		return K % hashsize[H.sizeindex];   
	}
	
	/*(07)开放定址法寻找下一探查位置 */
	/*
	开放定址法:H(key)=(H(key)+ d)mod m(其中 m 为哈希表的表长,d 为一个增量,mod表示取余);
	获取d值的方法为:线性探测法di=1,2,…,m-1
	*/
	void collision(HashTable H, int *p)	//简单的移位 
	{
		*p = (*p+1)%hashsize[H.sizeindex]; 
	}
	
	/* (08)输出哈希表中关键字 */
	void PrintHash(HashTable H)
	{
		int i, v;
		
		v = hashsize[H.sizeindex];
		
		printf("哈希表容量为:%d,现有元素:%d 个,表中元素为:\n", v, H.count);
		
		for(i=0; i<v; i++)
		{
			if(H.elem[i]!=NULLKEY)
				printf("%d ",H.elem[i]);
		}
		
		printf("\n");
	}

	/* 测试*/
	int main(int argc, char *argv[])
	{	
		Table T;
		HashTable H;
		
		printf("创建并输出一个查找表...\n");
		{
			FILE *fp;
			
			fp = fopen("TestData_Table.txt", "r");	
			Create(fp, &T, Max);	
			Traverse(T, PrintKey);	
			printf("\n");
		}	
		PressEnter; 
		
		printf("▼1、2、3、4、5、6、7、8\n▲函数 CreateHash等 测试...\n");	//1、2、3、4、5、6、7、8.函数CreateHash等测试		
		{
			printf("创建一个哈希表,并输出其中的关键字:\n");	
			CreateHash(&H, T);	
			PrintHash(H);	
			printf("\n");
		}	
		PressEnter; 
	
		printf("▼\n▲查找测试...\n");										//查找测试
		{ 
			Status r;
			KeyType key = 20;
			int p = 0;
			
			printf("查找关键字 %d ...\n", key);
			r = SearchHash(H, key, &p);
			if(r==DUPLICATE)
				printf("查找成功,%d 在哈希表下标为 %d 的位置。\n", key, p);
			else
				printf("查找失败!\n");
			printf("\n");
		}	
		PressEnter; 
			
		return 0;
	}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
哈希是一种利用哈希函数进行快速查找的数据结构C语言可以通过数组和指针实现哈希。 首先需要定义一个哈希函数,将关键字转换成哈希的位置。可以使用简单的取模运算,将关键字的值除以哈希大小取余数得到哈希位置。 例如,哈希大小为10,关键字为20,则哈希位置为20%10=2。 接下来,定义一个结构体来示哈希中的每个元素,包括关键字和值。 ```c struct hash_element { int key; int value; }; ``` 然后,定义一个哈希数组,将每个元素插入到哈希中。如果哈希位置已经被占用,可以使用链来解决冲突。 ```c #define HASH_SIZE 10 struct hash_element *hash_table[HASH_SIZE]; void insert(int key, int value) { int index = key % HASH_SIZE; struct hash_element *element = malloc(sizeof(struct hash_element)); element->key = key; element->value = value; if (hash_table[index] == NULL) { hash_table[index] = element; } else { struct hash_element *p = hash_table[index]; while (p->next != NULL) { p = p->next; } p->next = element; } } int search(int key) { int index = key % HASH_SIZE; struct hash_element *p = hash_table[index]; while (p != NULL) { if (p->key == key) { return p->value; } p = p->next; } return -1; } ``` 这里的insert函数将关键字和值封装成一个结构体,然后根据哈希函数计算出哈希位置。如果该位置为空,直接插入元素;否则,遍历链直到找到空位置插入。 search函数根据哈希函数计算出哈希位置,然后遍历链查找关键字。 以上是一个简单的哈希实现,可以根据实际需求进行改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值