首页 > 代码库 > 数据结构之哈希表

数据结构之哈希表

仅给出一个以“除留余数法”+“开放定址法(线性探测再散列)”实现的哈希表代码:

#pragma once

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

#define OK 1
#define ERROR -1

#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)< (b))
#define LQ(a,b) ((a)<=(b))

typedef int KeyType;
typedef int info;

typedef struct
{
	KeyType key;
	//info otherinfo;
}ElemType;

typedef struct
{
	ElemType *elem;
	int count;		 //当前hash表元素个数
	int sizeindex;	 //hashsize[sizeindex]为当前hash表当前容量
}HashTable;

int InitHashTable(HashTable &H); // 构造一个空的哈希表
void DestroyHashTable(HashTable &H);
int Hash(KeyType K); // 除留余数法(m为表长,全局变量)
void collision(int &p,int d);// 开放定址法处理冲突:线性探测再散列
int SearchHash(HashTable H,KeyType K,int &p,int &c);   //搜索的是关键字
int InsertHash(HashTable &H,ElemType e);			   //插入的是元素
void RecreateHashTable(HashTable &H) /* 重建哈希表 */;
void TraverseHash(HashTable H);

#include "hash.h"

#include <stdio.h>
#include <stdlib.h>

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

int InitHashTable(HashTable &H)	// 构造一个空的哈希表
{ 
	int i;

	H.count=0; // 当前元素个数为0
	H.sizeindex=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 OK;

}  //InitHashTable

void DestroyHashTable(HashTable &H)	 //哈希表H存在,销毁哈希表H
{ 
	if (H.elem != NULL) free(H.elem);
	H.elem=NULL;
	H.count=0;
	H.sizeindex=0;
} //DestroyHashTable

int Hash(KeyType K)	   // 除留余数法(m为表长,全局变量)
{ 
	return K%m;
} //Hash

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

//在开放地址hashH中查找关键字K的元素,若查找成功,以p指示待查元素数据在表中位置并返回SUCCESS
//否则以p指示插入位置并返回UNSUCCESS
//c用以计冲突次数,其初值为0,供建表插入时参考
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))
	{
		collision(p,++c); //冲突检测
		if(c>=m) break;
	}

	if(H.elem[p].key!=NULLKEY&&EQ(K,H.elem[p].key))
		return SUCCESS;
	else 
		return UNSUCCESS;
}//SearchHash

int InsertHash(HashTable &H,ElemType e)
{ 
	// 查找不成功时插入数据元素e到开放定址哈希表H中,并返回OK;若冲突次数过大,则重建哈希表
	int c,p;
	c=0;
	if(SearchHash(H,e.key,p,c)) // 表中已有与e有相同关键字的元素
		return DUPLICATE;
	else if(c<hashsize[H.sizeindex]/2) // 冲突次数c未达到上限,(c的阀值可调)
	{
		// 插入e
		H.elem[p]=e;
		++H.count;
		return OK;
	}
	else
		RecreateHashTable(H); // 重建哈希表
	return ERROR;
}

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.sizeindex++; // 增大存储容量
	m=hashsize[H.sizeindex];

	p=(ElemType*)realloc(H.elem,m*sizeof(ElemType));
	if(!p)
		exit(-1); // 存储分配失败

	H.elem=p;
	for(i=0;i<m;i++)
		H.elem[i].key=NULLKEY; // 未填记录的标志(初始化)

	for(p=elem;p<elem+count;p++) // 将原有的数据按照新的表长插入到重建的哈希表中
		InsertHash(H,*p);

	free(elem);elem = NULL;
}//RecreateHashTable

void TraverseHash(HashTable H)
{
	int i;
	for (i = 0; i < m; i++)
		printf("%2d ", i);
	putchar('\n');
	for (i = 0; i < m; i++)
		if (H.elem[i].key != NULLKEY)
			printf("%2d ", H.elem[i].key);
		else
			printf("   ");
	putchar('\n');
	putchar('\n');
}

测试代码:

int main()
{
	HashTable H;
	int i;

	KeyType arr[] = {19, 14, 23, 01, 68, 20, 84, 27, 55, 11, 10, 79};  //关键字
	int n = sizeof(arr)/sizeof(arr[0]);

	InitHashTable(H);
	ElemType e;
	for (i = 0; i < n - 1; i++)//n
	{
		e.key = arr[i];
		InsertHash(H, e);   //插入的是元素
		printf("插入 %d 后:\n", e.key);
		TraverseHash(H);
	}

	printf("Hash表元素为:\n");
	TraverseHash(H);

	for (i = 0; i < n; i++)
	{
		int p = 0, c = 0;
		int ret = SearchHash(H, arr[i], p, c);	//查找的是关键字
		if(ret)
			printf("查找 %2d 成功, p = %2d, key = %2d, c = %d\n",arr[i], p, H.elem[p].key, c);
		else 
			printf("查找 %d 失败\n", arr[i]);
	}

	DestroyHashTable(H);
	getchar();
	return 1;
}

数据结构之哈希表