算法精解----9、链式哈希表

1、哈希表
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。

映射函数叫做散列函数,存放记录的数组叫做散列表。

冲突问题:两个不同的键映射到同一个位置

给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
这里写图片描述

2、链式哈希表
数组每个元素存放一个链表首地址,一个链表为一个桶。输入一个数据,函数h将其转化为整型数据k,根据k处理得到数组元素指向的桶,在桶(链表)中执行插入或删除操作。
对于一定数量的元素,桶的数量m决定每个桶的大概深度。桶少要存储所有数据则桶的深度大。若使用取余法作为哈希函数,那么m一般取不为2的幂的素数。
这里写图片描述

3、代码分析
(1)数据结构

//CHTbl是哈希表的整体属性
typedef struct _CHTbl{
    int size;//存入的数据个数
    int buckets;//桶数
    int (*h)(const void *data);//哈希函数,转换索引值
    int (*match)(const void *key1, const void *key2);
    void (*destroy)(void *data);
    LIST_ATTRITIVE *table;//数组首地址,数组中每个元素是一个链表(桶)的整体属性
}CHTbl;

typedef struct _LIST_ATTRITIVE
{
    int size;
    void (*destroy)(void (*data));
    LIST_ELEMENT *head;
    LIST_ELEMENT *tail;
}LIST_ATTRITIVE; 

typedef struct _LIST_ELEMENT
{
    void *data;
    struct _LIST_ELEMENT *next;
}LIST_ELEMENT;

(2)链式哈希表初始化:初始化CHTbl,为每个一级链表元素LIST_ATTRITIVE分配空间,CHTbl中数组table指向每个一级链表元素。

#include <stdio.h>
#include <string.h>
#include "chtbl.h"
#include  "../SingleLink/single_list.h"

//确定桶数,初始化每个桶的链表, 
int chtbl_init(CHTbl *htbl, int bucket, int (*h)(const void *key), 
                int (*match)(const void *key1, const void *key2), void (*destroy)(void *data))
{
    int i;

    //为数组每个元素指向的桶属性分配空间 ,该空间长期有效 
    if((htbl->table = (LIST_ATTRITIVE *)(malloc(bucket * sizeof(LIST_ATTRITIVE)))) == NULL)
        return -1;
    htbl->buckets = bucket;
    for(i = 0; i < bucket; i++)
    {
        list_init(&htbl->table[i], 0 , destroy, NULL, NULL);
    }
    htbl->h = h;
    htbl->match = match;
    htbl->destroy = destroy;
    htbl->size = 0;
    return 0;
}

void chtbl_destroy(CHTbl *htbl)
{
    int i; 
    for(i = 0; i < htbl->buckets; i++)
    {
        list_destroy(&htbl->table[i]);
    }
    free(htbl->table);
    memset(htbl, 0 sizeof(CHTbl));
    return;
}

//插入元素,只需要找到桶,在链表尾部插入 
int chtbl_insert(CHTbl *htbl, const void *data)
{
    void *temp;
    int bucket, retval;
    temp = (void *)data;
    if(chtbl_lookup(htbl, &temp) == 0)
        return 1;

    //处理data得到该放入哪个桶 
    bucket = htbl->h(data) % htbl->buckets;

    //在该桶指向的链表的尾部插入 
    if((retval = list_ins_next(&htbl->table[bucket], NULL, data)) == 0)
        htbl->size++;
    return retval;
}

//删除元素, 要便利对应桶的链表找到该元素 
int chtbl_remove(CHTbl *htbl, void **data)
{
    LIST_ELEMENT *element, *prev;
    int bucket;
    bucket = htbl->h(*data) % htbl->buckets;
    prev = NULL;

    //遍历 桶指向的链表
    for(element = htbl->table[bucket]->head; element != NULL; element = element->next)
    {
        if(htbl->match(*data, element->data))
        {
            if(list_rem_next(&htbl->table[bucket], prev, data) == 0)
            {
                htbl->size--;
                return 0;
            }
            else
            {
                return -1;
            }
        }
        //prev是匹配之间那个为匹配的元素 
        prev = element;
    }
    return -1;
}

int chtbl_lookup(CHTbl *htbl, void **data)
{
    LIST_ELEMENT *element;
    int bucket;
    bucket = htbl->h(*data) % htbl->buckets;
    for(element = htbl->table[bucket]->head; element != NULL; element = element->next)
    {
        if(htbl->match(*data, element->data))
        {
            *data = element->data;
            return 0;   
        } 
    }
    return -1;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值