9、链式哈希表

来源:互联网 发布:域名属于知识产权吗 编辑:程序博客网 时间:2024/06/01 20:16

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;}
原创粉丝点击