C语言哈希表实现

本文提供一种C语言HASH表的实现方法,包括插入、删除、查找操作,但不包括hash值的计算方法。
引用:
C语言快速判断素数的两种方法

一、基本结构

在这里插入图片描述

  1. 每个cell仅记录第一个元素,采用单向链表方式处理hash冲突。
  2. hash表大小使用素数,即cell数组的大小。

二、定义

hash表仅需记录cell数组指针、数组大小,cell仅需记录同hash值的第一个元素,如果没有元素则为NULL。

typedef struct hash_cell_struct hash_cell_t;
typedef struct hash_table_struct hash_table_t;

struct hash_cell_struct
{
    void*           data;
};

struct hash_table_struct
{
    hash_cell_t*    arr;
    uint32          size;
};

用户定义的数据结构体还需要增加一个void * 类型的指针,用于处理hash冲突的单向链表。如果一个结构体同时存在多个hash表中,那么相应的也需要多个void * 指针。

三、接口

1. 创建hash表

hash_table_t* hash_create(
    uint32          n	/* hash表大小 */
)
{
    hash_table_t*   table;

    /* 获取合适的实际哈希表大小 */
    while (!is_prime_fast(n))
        n++;
    /* 创建 */
    RET_IF_NULL(table = malloc(sizeof(hash_table_t) + n * sizeof(hash_cell_t)), NULL);
    table->arr = (hash_cell_t*)(table + 1);
    table->size = n;
    memset(table->arr, 0, n * sizeof(hash_cell_t));
    return table;
}

2. 释放hash表

void hash_free(
    hash_table_t*       table
)
{
    free(table);
}

3. INSERT

/* 功能: 插入元素N到hash表 */
/* TYPE: 数据结构体的类型
 * HASH: 处理冲突的void*成员名
 * TABLE: hash表
 * FOLD: hash值
 * N: 要插入的数据结构体 */
#define HASH_INSERT(TYPE, HASH, TABLE, FOLD, N)\
do {\
    hash_cell_t*    _cell;\
    \
    _cell = (hash_cell_t*)&((TABLE)->arr[(uint32)FOLD % (TABLE)->size]);\
    (N)->HASH = _cell->data;\
    _cell->data = N;\
} while (0)

4. DELETE

/* 功能: 在hash表中删除元素N */
/* TYPE: 数据结构体的类型
 * HASH: 处理冲突的void*成员名
 * TABLE: hash表
 * FOLD: hash值
 * N: 要删除的数据结构体 */
#define HASH_DELETE(TYPE, HASH, TABLE, FOLD, N)\
do {\
    hash_cell_t*    _cell; \
    TYPE*           _item;\
    \
    _cell = (hash_cell_t*)&((TABLE)->arr[(uint32)FOLD % (TABLE)->size]); \
    if ((N) == _cell->data)\
    {\
        _cell->data = (N)->HASH;\
    }\
    else\
    {\
        _item = _cell->data;\
        while (_item->HASH != N)\
            _item = _item->HASH;\
        _item->HASH = (N)->HASH;\
    }\
} while (0)

5. SEARCH

/* 功能: 获取第n个cell的第一个元素 */
#define HASH_GET_NTH_FIRST(TABLE, NCELL)    (((hash_cell_t*)&((TABLE)->arr[NCELL]))->data)

/* 功能: 获取下一个元素 */
#define HASH_GET_NEXT(HASH, N)              ((N)->HASH)

/* 功能: 在hash表中查找元素 */
/* HASH: 处理冲突的void*成员名
 * TABLE: hash表
 * FOLD: hash值
 * N: 要删除的数据结构体
 * TEST: 识别同hash值元素的测试语句 */
#define HASH_SEARCH(HASH, TABLE, FOLD, N, TEST)\
do {\
    N = HASH_GET_NTH_FIRST(TABLE, (uint32)FOLD % (TABLE)->size);\
    while (N)\
    {\
        if (TEST)\
            break;\
        N = HASH_GET_NEXT(HASH, N);\
    }\
} while (0)

测例

该hash表一般仅用于查找,并结合链表使用。测例中链表参考C语言通用双向链表

#include "list.h"
#include "hash.h"
#include <assert.h>

typedef struct item_struct item_t;
struct item_struct
{
    uint32      value;

    void*       hash;	/* 处理hash冲突用的单向链表指针域 */
    LIST_NODE_T(item_t) link;
};
typedef LIST_BASE_NODE_T(item_t) item_lst_t;

/* 功能: 测试hash表 */
void test_hash()
{
    item_lst_t      lst_items = { 0 };
    hash_table_t*   table;
    item_t*         item;
    uint32          i;

    table = hash_create(100);
    /* 插入1000个元素, 直接以value 0~999作为hash值 */
    for (i = 0; i < 1000; i++)
    {
        item = malloc(sizeof(item_t));
        item->value = i;
        LIST_ADD_LAST(link, lst_items, item);
        HASH_INSERT(item_t, hash, table, i, item);
    }
	/* 查找, 一定存在, 同时删除其中值为偶数的元素 */
    for (i = 0; i < 1000; i++)
    {
        HASH_SEARCH(hash, table, i, item, item->value == i);
        assert(item);
        if (i % 2 == 0)
        {
            HASH_DELETE(item_t, hash, table, i, item);
            LIST_REMOVE(link, lst_items, item);
            free(item);
        }
    }
	/* 再次查找, 一定只有值为奇数的元素存在, 也删掉 */
    for (i = 0; i < 1000; i++)
    {
        HASH_SEARCH(hash, table, i, item, item->value == i);
        if (i % 2 == 0)
        {
            assert(item == NULL);
        }
        else
        {
            assert(item);
            HASH_DELETE(item_t, hash, table, i, item);
            LIST_REMOVE(link, lst_items, item);
            free(item);
        }
    }
	/* 遍历hash表每个CELL, 因为已经删完一定都为空 */
    for (i = 0; i < table->size; i++)
    {
        assert(HASH_GET_NTH_FIRST(table, i) == NULL);
    }
    
    hash_free(table);
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值