哈希表 开放定址法

/*
*哈希表
*/
#include<stdio.h>
#include<stdlib.h>

#define NULLKEY 0//0为无记录标志
#define N 10//数据元素个数

typedef int KeyType;//设关键字域为整型
typedef struct 
{
	KeyType key;
	int ord;
}ElemType;//数据元素类型

#define EQ(a,b) ((a)==(b))

int hashsize[]={11,19,29,37};//哈希表容量递增表 一个合适的素数序列
int m=0;//哈希表表长 全局变量

typedef struct
{
	ElemType *elem;//数据元素存储基址 动态分配数组
	int count;//当前数据元素个数
	int size_index;//hashsize[size_index]为当前容量
}HashTable;


#define SUCCESS 1
#define UNSUCCESS 0
#define DUPLICATE -1

/* 操作结果: 构造一个空的哈希表 */
int initHashTable(HashTable *H)
{
	int i;

	(*H).count=0;//当前元素个数为0
	(*H).size_index=0;//初始存储容量为hashsize[0]
	m=hashsize[0];
	(*H).elem=(ElemType *)malloc(m*sizeof(ElemType));
	if(!(*H).elem)
		exit(0);//存储分配失败
	for(i=0;i<m;i++)
		(*H).elem[i].key=NULLKEY;//未填记录的标记

	return 1;
}

/* 初始条件:哈希表H存在*/
/* 操作结果:销毁哈希表H*/
void destroyHashTable(HashTable *H)
{
	free((*H).elem);
	(*H).elem=NULL;
	(*H).count=0;
	(*H).size_index=0;
}

/* 一个简单的哈希函数(m为表长 全局变量)*/
unsigned Hash(KeyType K)
{
	return K%m;
}

/*线性探测再散列*/
void collision(int *p,int d)
{
	*p=(*p+d)%m;//开放定址法处理冲突
}

/* 在开放定址哈希表H中查找关键码为K的元素,若查找成功,以p指示待查数据 */
/* 元素在表中位置,并返回SUCCESS;否则,以p指示插入位置,并返回UNSUCCESS */
/* c用以计冲突次数,其初值置零,供建表插入时参考 */
int searchHash(HashTable H,KeyType K,int *p,int *c)
{
	*p=Hash(K);//求得哈希地址
	while(H.elem[*p].key!=NULLKEY&&!EQ(K,H.elem[*p].key))//该位置中填有记录 并且关键字不相等
	{
		(*c)++;
		if(*c<m)
			collision(p,*c);//求得下一探查地址p
		else
			break;
	}
	if EQ(K,H.elem[*p].key)
		return SUCCESS;//查找成功 p返回待查数据元素位置
	else
		return UNSUCCESS;//查找不成功(H.elem[p].key==NULLKEY p返回的是插入的位置)
}

int insertHash(HashTable *,ElemType);//对函数的声明

void recreateHashTable(HashTable *H)//重建哈希表
{
	int i,count=(*H).count;

	ElemType *p,*elem=(ElemType *)malloc(count*sizeof(ElemType));

	p=elem;

	printf("重建哈希表\n");
	for(i=0;i<m;i++)//保存原有的数据到elem中
		if(((*H).elem+i)->key!=NULLKEY)//该单元有数据
			*p++=*((*H).elem+i);
	(*H).count=0;
	(*H).size_index++;//增大存储容量
	m=hashsize[(*H).size_index];
	p=(ElemType *)realloc((*H).elem,m*sizeof(ElemType));
	if(!p)
		exit(0);//存储分配失败
	(*H).elem=p;

	for(i=0;i<m;i++)
		(*H).elem[i].key=NULLKEY;//未填记录买的标志(初始化)
	for(p=elem;p<elem+count;p++)//将原有的数据按照新的表长插入到重建的哈希表中
		insertHash(H,*p);
}

/* 查找不成功时插入数据元素e到开放定址哈希表H中,并返回1 */
/* 若冲突次数过大,则重建哈希表 */
int insertHash(HashTable *H,ElemType e)
{
	int c,p;

	c=0;
	if(searchHash(*H,e.key,&p,&c))//表中已有与e有相同关键字的元素
		return DUPLICATE;
	else if(c<hashsize[(*H).size_index]/2)//冲突次数c未达到上线 c的阀值可调
	{
		(*H).elem[p]=e;//插入e
		++(*H).count;

		return 1;
	}
	else
		recreateHashTable(H);//重建哈希表

 return 0;
}

/* 按哈希地址的顺序遍历哈希表 */
void traverseHash(HashTable H,void(*Vi)(int ,ElemType))
{
	int i;

	printf("哈希地址0~%d\n",m-1);
	for(i=0;i<m;i++)
	{
		if(H.elem[i].key!=NULLKEY)//有数据
			Vi(i,H.elem[i]);
	}
}

/* 在开放定址哈希表H中查找关键码为K的元素,若查找成功,以p指示待查数据 */
/* 元素在表中位置,并返回SUCCESS;否则,返回UNSUCCESS */
int find(HashTable H,KeyType K,int *p)
{
	int c=0;

	*p=Hash(K);//求得哈希地址
	while(H.elem[*p].key!=NULLKEY&&!EQ(K,H.elem[*p].key))//该位置中填有记录.并且关键字不相等
	 { 
		c++;
		if(c<m)
		  collision(p,c); //求得下一探查地址p 
		else
		  return UNSUCCESS; // 查找不成功(H.elem[p].key==NULLKEY) 
	 }
	 if EQ(K,H.elem[*p].key)
		return SUCCESS; //查找成功,p返回待查数据元素位置 
	 else
		return UNSUCCESS; // 查找不成功(H.elem[p].key==NULLKEY) 

}

void printHash(int p,ElemType r)
{
	printf("address=%d (%d %d)\n",p,r.key,r.ord);
}
int main()
{
	 ElemType r[N]={{17,1},{60,2},{29,3},{38,4},{1,5},{2,6},{3,7},{4,8},{60,9},{13,10}};
	 HashTable h;
	 int i,p;
	 int j;
	 KeyType k;

	 initHashTable(&h);
	 for(i=0;i<N-1;i++)//插入前N-1个记录
	 {
		 j=insertHash(&h,r[i]);
		 if(j==DUPLICATE)
			 printf("表中已有关键字尾%d的记录 无法再插入记录(%d %d)\n",r[i].key,r[i].key,r[i].ord);
	 }

	 printf("按哈希地址的顺序遍历哈希表\n");
	 traverseHash(h,printHash);
	 printf("\n\n");

	 printf("请输入带查找记录的关键字:");
	 scanf("%d",&k);
	 j=find(h,k,&p);
	 if(j==SUCCESS)
		 printHash(p,h.elem[p]);
	 else
		 printf("没找到\n");
	printf("\n\n");

	 j=insertHash(&h,r[i]);//插入第N个记录
	 if(j==0)//j==ERROR 重建哈希表
		 j=insertHash(&h,r[i]);//重建哈希表后重新插入第N个记录

	 printf("按哈希地址的顺序遍历重建后的哈希表\n");
	 traverseHash(h,printHash);
	 printf("\n\n");

	 printf("请输入带查找记录的关键字:");
	 scanf("%d",&k);
	 j=find(h,k,&p);
	 if(j==SUCCESS)
		 printHash(p,h.elem[p]);
	 else
		 printf("没找到\n");
	printf("\n\n");

	 destroyHashTable(&h);
	 printf("哈希表销毁成功!");
	 printf("\n\n");

	 return 0;
}

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值