linux c实现通用hash表

通用哈希散列表C语言实现

此博客只有代码,hash表概念等,请自行学习。此次hash中使用链表为本人所写。后续改写此hash表,使用内核链表,详情请查看下一个博客。

代码块

common.h:

#pragma once
#ifndef _COMMON_H_
#define _COMMON_H_

#include 
#include 
#include 

#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上均测试通过。

你可能感兴趣的:(c/c++,Linux,算法)