数据结构之哈希表
仅给出一个以“除留余数法”+“开放定址法(线性探測再散列)”实现的哈希表代码:
#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); //搜索的是keyword 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中查找keywordK的元素,若查找成功,以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有同样keyword的元素 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}; //keyword 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); //查找的是keyword 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; }