(一)步骤:
(0)构造一个HashTable数据结构;
1.定义一个hashTable的大小数组,里面存储的每个元素为素数,
包含一个元素指针,当前数组大小count,size_index(hashTable的大小索引,通过查表可以得到相应的hash表的大小)
(1)初始化hashTable,初始化count=0,根据size_index查表,开辟一个相应大小的数组,然后数组的每个元素 的值为空;
(2)定义一个hash函数:输入为key,输出为hash(key)即地址;
(3)解决冲突的 方法:
开放定址法:void collision(int *p, int d);
根据Hi=(H(key)+d)%M;M已知,输入为H(k),以及偏移量d,输出为新的H,这里相当于更新P;
(4) hashSearch, 如int hashSearch(HashTable H, KeyType key , int *p , int d){
//在hash表H中,查找关键字key,如果找到,则返回1,否则0,如果找到p为key的hash地址,
//如果没有找到,根据p,d解决冲突的方法,可以得到p待插入的地址;
p=hash(key);
while (如果p处的值非空 && p处的值不等于 key ){
根据再散列 collision(p,d)得到新的p;
更新d;
}
if(p处的值==key) 则返回1;
else 返回0;
}
(5) hashInsert(HashTable H ,KeyType key){
先调用hashSearch(),看看是否可以查找到key;
如果查不到,则插入;
}
----------------------
/*hash表之开放定址法处理冲突:*/
方法一:
/*
根据提示输入学生信息,然后输入查找学生的学号,如果有的话,输出学生姓名和位置,如果没有的话,提示没有该学生的信息。
*/
#import <Foundation/Foundation.h>
#define MAX 20
typedef struct
{
int num;
char name[20];
} ElemType; //定义查找的节点元素
typedef struct
{
ElemType *elem;
int count;
int sizeindex;
} HashTable; //定义哈希表
/*
HashTable中elem数组的下标就是hash地址。
elem数组元素的值就是关键字。
*/
int hash(int num) //定义哈希函数
{
int p;
p = num % 5;
return p;
}
void InitHash(HashTable *H)
{
int i;
H -> elem = (ElemType *)malloc(MAX * sizeof(ElemType));
H -> count = 0;
H -> sizeindex = MAX;
for (int i = 0; i < MAX; i++) {
H -> elem[i].num = 0; //初始化
}
}
/*从hashTable H中查找 关键字 key, 如果找到,则返回1,没有找到则返回0.
p为key的hash值,如果p已经被其他关键字占用,则根据解决冲突的方法,重新设置p;
最终p为存放key的地址;
*/
int hashSearch(HashTable H, int key, int *p)
{
int c = 0;
*p = hash(key);
while (H.elem[*p].num!=key && H.elem[*p].num!=0) { // p位置 被其他的不等于key的关键字占用
//通过二次探测再散列解决冲突
c = c + 1;
if (c%2 == 1) {
*p = *p + (c+1)*(c+1)/4;
}
else
{
*p = *p - (c*c)/4;
}
}
if (H.elem[*p].num == key) {
return 1;
}
else
{
return 0;
}
}
void insertHash(HashTable *H, ElemType e) //如果查找不到就插入元素
{
int p;
hashSearch(*H, e.num, &p);
H -> elem[p] = e;
++H -> count;
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
HashTable H;
int p, key;
ElemType e;
InitHash(&H);
for (int i = 0; i < 3; i++)
{
loop:printf("请输入第%d个学生的学号\n", i+1);
scanf("%d", &e.num);
if (!hashSearch(H, e.num, &p)) {
printf("输入第%d个学生名字\n", i+1);
scanf("%s", e.name);
insertHash(&H, e);
}
else
{
printf("该学号已经存在");
goto loop;
}
}
printf("请输入您要查找的学生学号:\n");
scanf("%d", &key);
if (hashSearch(H, key, &p)) {
printf("查找成功!学生的姓名是%s\n",H.elem[p].name);
printf("学生所在表中的位置是%d\n", p);
}
else
{
printf("您要查找的学生不存在!\n");
}
}
return 0;
}
----------------------------------
方法二:
/*
*哈希表
*/
#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;
}