哈希值的算法c语言实现,hash.cpp · 有时需要偏执狂/经典算法C语言实现 - Gitee.com...

本文介绍了两种散列表实现方法:拉链法(分离链接哈希表)与线性探测哈希。重点讲解了霍纳算法和伪随机序列在哈希函数中的应用,以及如何通过哈希冲突解决策略提高数据存储和检索效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include "search.h"

/***********************hash公共方法***********************/

/*

*使用霍纳算法+除留余数法hash字符串,返回0-M之间

* 基数是素数,很牛逼的做法。

*/

static int hashstring(char *v , int M)//以素数127 hash字符串

{

int hash = 0;

int a = 127;//素数hash

for( ; *v != '\0' ; v++){//霍纳算法

hash = (a*hash + *v)%M;

}

return hash;

}

/*

*使用霍纳算法+除留余数法hash字符串,返回0-M之间

* 基数是伪随机序列,很牛逼的做法。

*/

static int hashUniversal(char *v , int M)//通用hash,以伪随机素数 hash字符串

{

int hash = 0;

int a = 31415;//通过a是伪随机序列 hash

int b = 27168;

for( ; *v != '\0' ; v++ ){

hash = (a*hash + *v)%M;

a = a * b % (M-1);

}

return hash;

}

/***********************hash公共方法***********************/

/*******************拉链法实现散列表方法************************/

static SCHashNode* heads;//M矩阵,动态分配指针数组

int SCHCount = 0;//符号表大小

SCHashNode NewNode(SCHashNode head , Key * key , Value val)

{

SCHashNode x = (SCHashNode)malloc(sizeof(struct SCHashnode) );//分配结构体

x->next = head;

x->key = key;

x->val = val;

return x;//将x插入链表头

}

void SeparateChainingHashST_Init()//初始化数组M

{

int i;

heads = (SCHashNode *)malloc(MCount * sizeof(SCHashNode));//分配指针数组

for(i = 0 ; i < MCount ; i++)//初始化为空

heads[i] = NULL;

}

void SeparateChainingHashST_Put(Key * key , Value val)

{

SCHashNode x;

int hash;

hash = hashstring(key , MCount);

#ifdef BEBUG

printf("%s hash is %d\n",key , hash);

#endif

for(x = heads[hash] ; x != NULL ; x = x->next){//遍历命中则更新

if(strcmp(x->key , key) == 0){

x->val = val;

return ;

}

}

heads[hash] = NewNode(heads[hash] , key , val);//未命中插入链表前面

SCHCount++;

}

Value SeparateChainingHashST_Get(Key * key )

{

SCHashNode x;

int hash;

hash = hashstring(key , MCount);

for(x = heads[hash] ; x != NULL ; x = x->next){

if(strcmp(x->key , key) == 0){

return x->val;//命中

}

}

return 0;//未命中

}

int SeparateChainingHashST_Size()

{

return SCHCount;

}

/************************************************************/

/*******************线性探测实现散列表方法************************/

static int UserSetM = 20;//用户设定存储数组大小

static int LPHM = UserSetM;//实际存储数组大小,这个数值会变化,使得散列表的使用率永远都不会查过1/2,减少探测次数。

static LPHCount = 0;//符号表中元素个数

static LPHashNode Heads;//用于动态分配数组

static void ReSize_LPHM(int M)//重新调整数组大小,代价很大,重新分配,重新插入

{

LPHashNode x;

x = heads;//保持原始数组地址

heads = (LPHashNode)malloc(M * sizeof(struct LPHashnode));//重新分配LPHM对应的数组空间

for(i = 0 ; i < LPHM ; i++)//初始化为空

heads[i] = NULL;

for(i = 0 ; i < M ; i++){//将原始数组有键的位置,重新插入

if(x[i].key != NULL)

LinearProbingHashST_Put(x[i].key , x[i].val);

}

free(x);//释放原始数组位置。

}

void LinearProbingHashST_Init()

{

int i;

Heads = (LPHashNode)malloc(LPHM * sizeof(struct LPHashnode));//分配LPHM对应的数组空间

for(i = 0 ; i < LPHM ; i++)//初始化为空

Heads[i] = NULL;

}

void LinearProbingHashST_Put(Key* key , Value val)

{

int i;

if(LPHCount > LPHM / 2){//保证使用率不大于1/2.

LPHM = 2*LPHM;//扩大两倍

Resize_LPHM(LPHM);//重新调整

}

i = hashstring(key , LPHM);//hash

for( ; Heads[i].key != NULL ; i = (i + 1)%LPHM)//循环查找

if(strcmp(Heads[i].key , key) == 0){//遍历命中则更新

Heads[i].val = val;

return ;

}

Heads[i].key = key;//未命中,则插入空白位置

Heads[i].val = val;

LPHCount++;//元素加1

}

Value LinearProbingHashST_Get(Key* key )

{

int i = hashstring(key , LPHM);

for( ; Heads[i].key != NULL ; i = (i + 1)%LPHM)//循环查找

if(strcmp(Heads[i].key , key) == 0){//遍历命中则返回

return Heads[i].val;

}

return 0;//遇到空未命中,返回空

}

void LinearProbingHashST_Delete(Key* key )

{

int i;

struct LPHashnode temp;

if(key == NULL)//key为空,直接返回

return ;

i = hashstring(key , LPHM);

while(Heads[i].key != NULL){//查找键直到遇到空为止(如果遇到空,那么肯定键不在表中)

if(strcmp(Heads[i].key , key) == 0)

break;

else

i = (i+1)%LPHM;

}

if(Heads[i].key == NULL)//遇到空,证明不在表中

return ;

Heads[i].key = NULL;//命中,则键清空

Heads[i].val = 0;

i = (i+1)%LPHM;//索引键簇下一个元素

while(Heads[i].key != NULL){//将键重新插入表

temp = Heads[i];//缓存键值

Heads[i].key = NULL;//将键清空

Heads[i].val = 0;

LPHCount--;

LinearProbingHashST_Put(temp.key , temp.val);//并重新插入

i = (i+1)%LPHM;

}

LPHCount--;//总体元素个数减1

if(LPHCount > 0&&LPHCount == LPHM / 8){//如果总体元素太少,为了节约空间,缩小LPHM

LPHM = LPHM/2;

ReSize_LPHM(LPHM);//消耗时间

}

}

int LinearProbingHashST_Size()

{

return LPHCount;

}

/************************************************************/

一键复制

编辑

Web IDE

原始数据

按行查看

历史

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值