今天我们主要的是用线性探测的方法处理哈希冲突的问题。
线性探测方法的具体实现如下:
test.h
#pragma once #include <stdio.h> #include <stddef.h> #include <stdlib.h> //我们在这里的hash表期望存储的数据是键值对这样的结构 #define HashMaxSize 1000 typedef enum Stat{ empty,//空状态 valid,//有效状态 deleted,//删除状态 }Stat; typedef int Hashtype; typedef int keytype; typedef int valtype; typedef size_t (*HashFunc)(keytype key); //这个结构表示的是哈希表中的一个元素 //这个元素同时包含了键值对 typedef struct Hashelme{ keytype key; valtype value; Stat stat; }Hashelme; typedef struct Hashtable{ Hashelme data[HashMaxSize]; size_t size;//哈希表当中元素的个数(【0,size)不能表示哈希表有效元素的区间 HashFunc func;//这是一个函数指针,指向的是hash函数 }Hashtable; void HashInit(Hashtable* ht); void HashDestroy(Hashtable* ht); void HashInsert(Hashtable* ht,keytype key,valtype value); //此时我们根据key找到value就可以了 int HashFind(Hashtable* ht,keytype key,valtype* value); void HashRemove(Hashtable* ht,keytype key); #include "hash1.h" size_t HashDefault(keytype key){ return key % HashMaxSize; } void HashInit(Hashtable* ht) { if(ht==NULL){ return ; } ht->size=0; ht->func=HashDefault; size_t i=0; //将哈希表每一个位置初始化为空状态 //表示从来没有被使用过 for(i=0;i<HashMaxSize;i++){ ht->data[i].stat=empty; } return; } void HashDestroy(Hashtable* ht) { if(ht==NULL){ return; } //将哈希表中的每一个位置都为无效状态 size_t i=0; for(i=0;i<HashMaxSize;i++){ ht->data[i].stat=empty; } ht->size=0; ht->func=NULL; return; } //插入数据 void HashInsert(Hashtable* ht,keytype key,valtype value) { if(ht==NULL){ return; } // 1、判定当前hash表能否继续插入元素,假设负载因子为0.8 if(ht->size>=0.8*HashMaxSize){ return;//当前的hash表已经达到了负载因子的上限不能再继续进行插入了 } //2、根据key计算出offset(由hash函数计算出有效位置的下标; size_t offset=ht->func(key); //但是该位置可能之前已经被别的数据占据了,所以我们就要先判断出 //该位置是否能够进行插入当前的数据,要是不能的话我们就进行offset进行往后查找 while(1){ //先判断当前计算出的位置能否放入当前的数据 if(ht->data[offset].stat!=valid) { //一旦我们计算出的位置不是有效位置,那么我们就可以把数据进行插入了 //这个就是我们处理哈希冲突的线性探测的方法; ht->data[offset].key=key; ht->data[offset].value=value; //插入完成之后将该位置设置成有效状态 ht->data[offset].stat=valid; //然后将哈希表的有效元素+1 ht->size++; return; } //走到这里就说明当前我们计算出的当前位置不能放置当前的数据 //判断当前位置上的元素是否和我们要插入的元素相等 else if(ht->data[offset].stat==valid && ht->data[offset].key==key) { //走到这里就说明存在相同的元素, //在这里我们约定这个哈希表中不存在重复的元素 //所以我们就认为失败返回 return; } //则更新offset的值进行往后查找 else { offset++; if(offset>=HashMaxSize){ //如果查找到hash的末尾还没有找到一个可插入的位置 //那么我们就重置从头开始继续查找 offset=0; } }//else结束 }//while循环结束 } void HashPrint(Hashtable* ht,const char* msg) { printf("[%s]\n",msg); int i=0; for(;i<HashMaxSize;i++) { if(ht->data[i].stat==valid) { printf("(%d:%d,%d) ",i,ht->data[i].key,ht->data[i].value); } } printf("\n"); } //此时我们根据key找到value就可以 int HashFind(Hashtable* ht,keytype key,valtype* value) { if(ht==NULL){ return 0;//非法输入 } //判断当前哈希表中是否有效元素 if(ht->size==0){ return 0;//空哈希表 } //根据当前元素计算出key值 size_t offset=ht->func(key); //然后根据offset向后进行查找 while(1) { //在当前元素的状态为有效元素 if(ht->data[offset].stat==valid) { if(ht->data[offset].key==key) { //找到了 *value=ht->data[offset].value; return 1; } //当前位置存放的不是待查找的元素, //更新offset继续进行查找 else { offset++; if(offset>=HashMaxSize){ //重新进行二次查找 offset=0; } } } else if(ht->data[offset].stat==empty) { //说明待查找的元素不在hash表中,查找失败 return 0; } }//while循环结束 return 0; } void HashRemove(Hashtable* ht,keytype key) { if(ht==NULL) { return; } if(ht->size==0) { return;//空哈希表 } int offset=ht->func(key); while(1) { if(ht->data[offset].stat==valid && ht->data[offset].key==key) { //找到了要删除的元素 //将其状态置为可删除状态 ht->data[offset].stat=deleted; ht->size--; return; } else if(ht->data[offset].stat==empty) { //没有找到要删除的元素 return; } else { offset++; if(offset>=HashMaxSize) offset=0; } }//while循环结束 return; } ////////////////////////////////////////////////////////// //////////////////test/////////////////////////////////// ////////////////////////////////////////////////////////// #define TEST_HEADER printf("\n==============%s===========\n",__FUNCTION__); void test1() { TEST_HEADER; Hashtable ht; HashInit(&ht); printf("expext size is 0,actual size is %d\n",ht.size);//在这里用的“." //因为ht在这里是一个常量而不是一个指针类型的; printf("expect func is %p,actual func is %p\n",HashDefault,ht.func); } void test2() { TEST_HEADER; Hashtable ht; HashInit(&ht); HashInsert(&ht,1,1); HashInsert(&ht,1,10); HashInsert(&ht,2,20); HashInsert(&ht,1000,100); HashInsert(&ht,2000,200); HashPrint(&ht,"插入5个元素"); } void test3() { TEST_HEADER; Hashtable ht; HashInit(&ht); HashInsert(&ht,1,1); HashInsert(&ht,1,10); HashInsert(&ht,2,20); HashInsert(&ht,1000,100); HashInsert(&ht,2000,200); HashPrint(&ht,"插入5个元素"); printf("\n"); valtype value; int ret=HashFind(&ht,1000,&value); printf("expct return is 1,actual return is %d\n",ret); printf("expect value is 100,actual value is %d\n",value); printf("\n"); ret=HashFind(&ht,2000,&value); printf("expct return is 1,actual return is %d\n",ret); printf("expect value is 200,actual value is %d\n",value); } void test4() { TEST_HEADER; Hashtable ht; HashInit(&ht); HashInsert(&ht,1,1); HashInsert(&ht,1,10); HashInsert(&ht,2,20); HashInsert(&ht,1000,100); HashInsert(&ht,2000,200); HashPrint(&ht,"插入5个元素"); printf("\n"); HashRemove(&ht,2); HashPrint(&ht,"删除元素2: "); HashRemove(&ht,1000); HashPrint(&ht,"删除元素1000: "); } int main() { test1(); test2(); test3(); test4(); return; } 
第二种方法具体见下一篇博客!!