近来无聊,决定动手写点程序练练手,所以从最基础的哈希表数据结构开始,全程参考的此处的GitHub项目
第一次尝试搭建极简的C语言开发环境(对于编程小白不太友好,不建议),网上教程较多,不赘述,比如这、这
哈希表
哈希冲突是不可避免的,常用的解决方法有两种开放地址法、链表法
本文基于开放地址法,开放地址法中有三种方式来寻找其他的位置,分别是**「线性探测」、「二次探测」、「再哈希法」**。本文采用线性探测法,即若插入位置已经有值,则向下顺序寻找空位置进行插入。
哈希表应该具有的API接口
构建每个元素和和哈希表的数据结构
typedef struct {
char* key;
char* value;
} ht_item;
typedef struct {
int size;
int count;
ht_item** items;
} ht_hash_table;
初始化元素:malloc申请新元素的空间,并将key和value对应赋值。
#include
#include
static ht_item* ht_new_item(const char* k, const char* v) {
ht_item* i = malloc(sizeof(ht_item));
i->key = strdup(k);
i->value = strdup(v);
return i;
}
初始化哈希表:malloc申请哈希表的空间,calloc申请存放元素地址的空间(与malloc不同的是申请的区域为初始化为0),并将size和count对应赋值。
ht_hash_table* new_ht() {
ht_hash_table* h = malloc(sizeof(ht_hash_table)) ;
h->size = 53;
h->count = 0;
h->items = calloc((size_t)h->size, sizeof(ht_item*))
return h;
}
删除:释放掉申请的内存,防止内存泄漏。注意释放的先后顺序,i和h最后才释放
static void ht_del_item(ht_item* i) {
free(i->key);
free(i->value);
free(i);
}
void ht_del_hash_table(ht_hash_table* h)
{
for(int i = 0;i <h->size;i++)
{
if(h->items[i] != NULL)
ht_delete_item(h->items[i]);
}
free(h->items);
free(h);
}
使用static关键字修饰的静态函数不能被其它文件调用,作用于仅限于本文件
程序其中用到的基础C语言的库函数:
头文件:#include
定义函数:void* malloc (size_t size);
参数说明:size 为需要分配的内存空间的大小,以字节(Byte)计。
函数说明:malloc() 在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的。如果希望在分配内存的同时进行初始化,请使用 calloc() 函数。
返回值:分配成功返回指向该内存的地址,失败则返回 NULL
头文件:#include
定义函数:char * strdup(const char *s);
函数说明:strdup()会先用maolloc()配置与参数s 字符串相同的空间大小,然后将参数s 字符串的内容复制到该内存地址,然后把该地址返回。该地址最后可以利用free()来释放。
返回值:返回一字符串指针,该指针指向复制后的新字符串地址。若返回NULL 表示内存不足。
定义函数:void* calloc (size_t num, size_t size);
函数说明:calloc() 在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0。所以它的结果是分配了 num*size 个字节长度的内存空间,并且每个字节的值都是0。
返回值:分配成功返回指向该内存的地址,失败则返回 NULL。
我们将使用一个通用字符串哈希函数
此哈希函数有两个步骤:
哈希表的大小为何是素数?。
static int ht_hash(const char* s, const int a, const int m)
{
long hash = 0;
const int len_s = strlen(s);
for (int i = 0; i < len_s; i++) {
hash += (long)pow(a, len_s - (i+1)) * s[i];
hash = hash % m;
}
return (int)hash;
}
int insert(ht_hash_table* h, const char* k, const char* v)
{
ht_item* i = ht_new_item(k,v);
int index = ht_hash(k,151,53);
if(h->count >= h->size)
return -1;
h->count++;
while(1)
{
if((h->items[index])==NULL)
{
h->items[index] = i;
return index;
}
index++;
if(index == h->size)
index = 0;
}
}
char* search(ht_hash_table* h, const char* k)
{
int index = ht_hash(k,151,53);
for (int i = 0; i < h->size;i++)
{
if(h->items[index]!=NULL)
if(strcmp(h->items[index]->key,k)==0)
return h->items[index]->value;
index++;
if(index == h->size)
index = 0;
}
return NULL;
}
void delete(ht_hash_table* h, const char* k)
{
int index = ht_hash(k,151,53);
for (int i = 0; i < h->size;i++)
{
if(h->items[index]!=NULL)
if(strcmp(h->items[index]->key,k) == 0)
{
ht_del_item(h->items[index]);
h->items[index] = NULL;
h->count--;
return ;
}
index++;
if(index == h->size)
index = 0;
}
return ;
}
int main(void)
{
ht_hash_table* ht=new_ht();
insert(ht,"niuniu","hahaha");
insert(ht,"shuoshuo","xixixi");
char* s = search(ht,"shuoshuo");
if(s==NULL)
printf("查找失败 %d\n",s);
else
printf(s);
delete(ht,"shuoshuo");
char* c = search(ht,"shuoshuo");
if(c==NULL)
printf("查找失败 %d\n",c);
else
printf(c);
ht_del_hash_table(ht);
return 0;
}
未完待续。。。
#include
#include
#include "hash_table.h"
void ht_delete_item(ht_hash_table* h){}
static ht_item* ht_new_item(const char* k, const char* v)
{
ht_item* i = malloc(sizeof(ht_item));
i->key = strdup(k);
i->value = strdup(v);
return i;
}
static void ht_del_item(ht_item* i)
{
free(i->key);
free(i->value);
free(i);
}
ht_hash_table* new_ht()
{
ht_hash_table* h = malloc(sizeof(ht_hash_table)) ;
h->size = 53;
h->count = 0;
h->items = calloc((size_t)h->size, sizeof(ht_item*));
return h;
}
void ht_del_hash_table(ht_hash_table* h)
{
for(int i = 0;i <h->size;i++)
{
if(h->items[i] != NULL)
ht_delete_item(h->items[i]);
}
free(h->items);
free(h);
}
static int ht_hash(const char* s, const int a, const int m)
{
long hash = 0;
const int len_s = strlen(s);
for (int i = 0; i < len_s; i++) {
hash += (long)pow(a, len_s - (i+1)) * s[i];
hash = hash % m;
}
return (int)hash;
}
int insert(ht_hash_table* h, const char* k, const char* v)
{
ht_item* i = ht_new_item(k,v);
int index = ht_hash(k,151,53);
if(h->count >= h->size)
return -1;
h->count++;
while(1)
{
if((h->items[index])==NULL)
{
h->items[index] = i;
return index;
}
index++;
if(index == h->size)
index = 0;
}
}
char* search(ht_hash_table* h, const char* k)
{
int index = ht_hash(k,151,53);
for (int i = 0; i < h->size;i++)
{
if(h->items[index]!=NULL)
if(strcmp(h->items[index]->key,k)==0)
return h->items[index]->value;
index++;
if(index == h->size)
index = 0;
}
return NULL;
}
void delete(ht_hash_table* h, const char* k)
{
int index = ht_hash(k,151,53);
for (int i = 0; i < h->size;i++)
{
if(h->items[index]!=NULL)
if(strcmp(h->items[index]->key,k) == 0)
{
ht_del_item(h->items[index]);
h->items[index] = NULL;
h->count--;
return ;
}
index++;
if(index == h->size)
index = 0;
}
return ;
}
int main(void)
{
ht_hash_table* ht=new_ht();
insert(ht,"niuniu","hahaha");
insert(ht,"shuoshuo","xixixi");
char* s = search(ht,"shuoshuo");
if(s==NULL)
printf("查找失败 %d\n",s);
else
printf(s);
delete(ht,"shuoshuo");
char* c = search(ht,"shuoshuo");
if(c==NULL)
printf("查找失败 %d\n",c);
else
printf(c);
ht_del_hash_table(ht);
return 0;
}