#include <stdio.h>
//基于线性探测法的散列表
//使用线性探测解决键冲突问题,核心思想就是利用数组空位,当使用
//哈希函数计算出数组索引后,开始检测该索引位置是否已经被使用,如
//果已经使用,则索引向后递增(如果超出数组索引,则需要进行回绕到
//数组起始索引),直到找到空位为止,或者数组空间已全部被使用,无
//法再扩冲,由于这里利用的是数组空间,所以通常情况下,需要该数组
//支持动态调整数组空间功能,当前简化了这步流程,仅使用静态数组进
//行分析。
#define TEST_CASE (1)
#define MAX_HASH_ENTRY 5
typedef struct
{
int used;
int key;
int val;
} HASH_ENTRY;
HASH_ENTRY hashTableEntrys[MAX_HASH_ENTRY] = {0};
int g_hashTableEntryCount = 0;
//正整数类型的KEY的散列函数
//通常采用除留余法,这里通过对KEY进行求余,使得KEY分布在hashTable
//的数组中,同时为了减少键冲突,除数通常选择为素数,比如当前示例
//选择为97
int hashFunctionForInt(int key)
{
// M 通常为素数
//hashKey = key % M
int hashKey = key % 97;
return hashKey;
}
//计算哈希表数组的索引
// 1首先算出hashKey
// 2 之后根据当前哈希表数组长度进行求余操作,避免计算出来的hashKey大于
// 数组长度,导致出现溢出
int hashIndex(int key)
{
int hashKey = hashFunctionForInt(key);
return hashKey % MAX_HASH_ENTRY;
}
//新增条目
//1 当前不支持动态调整数组空间,所以需要检测溢出的隐患
//2 进行数组空位查找
void put(int key, int val)
{
int index = hashIndex(key);
if ( g_hashTableEntryCount >= MAX_HASH_ENTRY )
{
printf("don't put, array full.\r\n");
return;
}
while ( hashTableEntrys[index].used )
{
index = (index + 1) % MAX_HASH_ENTRY;
}
hashTableEntrys[index].used = 1;
hashTableEntrys[index].key = key;
hashTableEntrys[index].val = val;
g_hashTableEntryCount++;
}
//查找
//这里有3种情况会退出循环
//1 没有对应的空位了,即没有找到需要的数组
//2 有对应的空位,但键值不是要查找的
//3 防止数组出现满的情况,这时候需要进行环绕检测,避免死循环
int get(int key)
{
int val = -1;
int index = hashIndex(key);
int curGetIndex = index;
while ( hashTableEntrys[index].used )
{
if ( curGetIndex == index )
{
break;
}
if ( hashTableEntrys[index].key == key )
{
val = hashTableEntrys[index].val;
break;
}
index = (index + 1) % MAX_HASH_ENTRY;
}
return val;
}
//删除
//线性探测法由于在进行查找时,遇到空位则停止,所以在进行删除
//时,后面数据的问题,比如当前要删除hashKey = 3,当删除第一个
//条目时,第一个位置出现了空洞,此时需要将后面项全部删除并重
//新插入,否则后面数据将无法访问。
// -------------------------
// |3|3|3|3| | | | | | | | |
// -------------------------
int delete(int key)
{
int find = 0;
int index = hashIndex(key);
while ( hashTableEntrys[index].used )
{
if ( hashTableEntrys[index].key == key )
{
find = 1;
break;
}
index = (index + 1) % MAX_HASH_ENTRY;
}
if ( find )
{
int curDeleteIndex = index;
hashTableEntrys[index].used = 0;
g_hashTableEntryCount--;
index = (index + 1) % MAX_HASH_ENTRY;
while ( hashTableEntrys[index].used && (curDeleteIndex != index) )
{
put(hashTableEntrys[index].key, hashTableEntrys[index].val);
hashTableEntrys[index].used = 0;
g_hashTableEntryCount--;
index = (index + 1) % MAX_HASH_ENTRY;
}
}
return find ? 0 : -1 ;
}
void testCase0()
{
put(1, 1);
put(2, 2);
put(3, 3);
put(4, 4);
put(5, 5);
put(6, 6);
put(7, 7);
printf("find key %d, val %d\r\n", 3, get(3));
printf("find key %d, val %d\r\n", 7, get(7));
}
void testCase1()
{
put(3, 3);
put(3, 3);
put(3, 3);
put(3, 3);
put(3, 3);
put(3, 3);
put(3, 3);
delete(3);
delete(3);
delete(3);
delete(3);
delete(3);
delete(3);
delete(3);
printf("find key %d, val %d\r\n", 3, get(3));
}
int main()
{
printf("max hashTable entry %d\r\n", MAX_HASH_ENTRY);
switch ( TEST_CASE )
{
case 0: testCase0(); break;
case 1: testCase1(); break;
default: break;
}
return 0;
}
基于线性探测法的散列表
最新推荐文章于 2023-01-27 17:16:21 发布