通用哈希散列表C语言实现
此博客只有代码,hash表概念等,请自行学习。此次hash中使用链表为本人所写。后续改写此hash表,使用内核链表,详情请查看下一个博客。
代码块
common.h:
#pragma once
#ifndef _COMMON_H_
#define _COMMON_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif
hash.h
#pragma once
#ifndef _HASH_H_
#define _HASH_H_
/*此方法采用的是连地址法*/
/*为了不将hash结构暴露在外面,所以就必须typedef*/
typedef struct hash hash_t;
//这是一个hash函数指针,对用户来说应该需要使用一个合适的hash函数
//第一个参数unsigned int指的是桶的大小 第二个参数是key值
typedef unsigned int(*hash_func_t)(unsigned int,void *);
/*返回的是hash表指针,创建hash表*/
hash_t *hash_alloc(unsigned int,hash_func_t);
void *hash_lookup_entry(hash_t *,void *,unsigned int );
void hash_add_entry(hash_t *, void *, unsigned int ,
void *, unsigned int );
void hash_free_entry(hash_t *,void *,int );
#endif /*_HASH_H_*/
hash.c
#include "hash.h"
#include "common.h"
//必须在前面声明typedef
typedef struct hash_node {
void *key;//查找依据
void *data;//数据块,一般是结构体
struct hash_node *prev;
struct hash_node *next;
}hash_node_t;
struct hash {
unsigned int buckets;//桶的个数(大小)
hash_func_t hash_func;//hash函数指针
hash_node_t **nodes;//hash表中存放的链表地址
};
//由于获得桶,和得到node节点的接口并不需要外部看见,所以定义成两个内部函数
/*根据key,得到桶*/
hash_node_t **hash_get_buckets(hash_t *hash,void *key);
/*根据key得到node节点*/
hash_node_t * hash_get_node_by_key(hash_t *hash,void *key,unsigned int key_size);
//创建hash表
hash_t *hash_alloc(unsigned int buckets, hash_func_t hash_func)
{
hash_t *hash = (hash_t *)malloc(sizeof(hash_t));
hash->buckets = buckets;
hash->hash_func = hash_func;
unsigned int size = buckets * sizeof(hash_node_t *);
hash->nodes = (hash_node_t **)malloc(size);
memset(hash->nodes,0x00, size);
return hash;
}
//判断
void* hash_lookup_entry(hash_t *hash, void *key, unsigned int key_size)
{
hash_node_t *node = hash_get_node_by_key(hash,key, key_size);
if (NULL == node) return NULL;
return node->data;
}
//添加hash节点
void hash_add_entry(hash_t *hash, void *key, unsigned int key_size,void *data, unsigned int data_size)
{
//首先需要查找看此数据项是否存在,如果存在则表明重复了,需要返回
if (hash_lookup_entry(hash, key, key_size)) {
printf("duplicate hash key\n");
return;
}
//创建节点,申请内存
hash_node_t *node = (hash_node_t*)malloc(sizeof(hash_node_t));
node->next = NULL;
node->prev = NULL;
node->key = malloc(key_size);
memcpy(node->key,key,key_size);
node->data = malloc(data_size);
memcpy(node->data, data, data_size);
//采用头插法,将节点插入到hash表中
//1.首先得取到桶
hash_node_t **bucket = hash_get_buckets(hash,key);
//如果没有节点
if (*bucket == NULL) {
*bucket = node;
}
else {
node->next = *bucket;
(*bucket)->prev = node;
*bucket = node;
}
}
//释放节点
void hash_free_entry(hash_t *hash, void *key, int key_size)
{
//释放节点首先得找到节点,
hash_node_t *node = hash_get_node_by_key(hash,key,key_size);
if (node == NULL) return;
if (node->prev) {
node->prev->next = node->next;
}
else{
//如果是第一个节点,就必须获得桶节点
hash_node_t **bucket = hash_get_buckets(hash,key);
*bucket = node->next;
}
if (node->next) {
node->next->prev = node->prev;
}
free(node->key);
free(node->data);
free(node);
}
//根据key得到buckets号
hash_node_t **hash_get_buckets(hash_t *hash, void *key)
{
unsigned int buckets = hash->hash_func(hash->buckets,key);
if (buckets >= hash->buckets){
printf("bad buckets loockup\n");
}
return &(hash->nodes[buckets]);
}
//通过key值,得到node节点
hash_node_t * hash_get_node_by_key(hash_t *hash, void *key, unsigned int key_size)
{
hash_node_t **buckets = hash_get_buckets(hash,key);
hash_node_t *node = *buckets;
if (node == NULL) return NULL;
//没有找到,有那两种可能,一种是节点就不存在,另一种是没有找到
while (node != NULL && memcmp(node->key, key, key_size) != 0) {
node = node->next;
}
return node;
}
main.c
#include "common.h"
#include "hash.h"
typedef struct student_t {
int eno;
char *name;
unsigned int age;
}student;
//编写hash函数
unsigned int hash_func(unsigned int bucktes, void *key)
{
return *((unsigned int*)(key)) % bucktes;
}
int main(int argc, char *argv[])
{
student stu_arry[] = {
{ 23,"aaa",20 },
{ 63,"bbb",30 },
{ 56,"ccc",40 },
{ 78,"gfr",20 },
{ 59,"bhk",30 },
{ 42,"cki",90 }
};
//首先创建hash table,
hash_t *hash = hash_alloc(80, hash_func);
//将数据添加进hash table;
int size = sizeof(stu_arry) / sizeof(stu_arry[0]);
int i = 0;
for (i = 0; i < size; i++)
{
hash_add_entry(hash, &stu_arry[i].eno, sizeof(stu_arry[i].eno),
&(stu_arry[i]), sizeof((stu_arry[i])));
}
//查找打印
printf("......................add end...............\n");
student *st = NULL;
for (i = 0; i < size; i++)
{
st = (student*)hash_lookup_entry(hash, &stu_arry[i].eno, sizeof(stu_arry[i].eno));
if (st) {
printf("st : eno %-10d name : %-10s age : %-10d\n", st->eno, st->name, st->age);
}
else {
printf("no node \n");
}
}
for (i = 0; i < size; i++)
{
hash_free_entry(hash, &stu_arry[i].eno, sizeof(stu_arry[i].eno));
}
printf("......................free end...............\n");
for (i = 0; i < size; i++)
{
st = (student*)hash_lookup_entry(hash, &stu_arry[i].eno, sizeof(stu_arry[i].eno));
if (st) {
printf("st : eno %-10d name : %-10s age : %-10d\n", st->eno, st->name, st->age);
}
else {
printf("no node \n");
}
}
system("pause");
return 0;
}
此代码在linux 与vs上均测试通过。