散列表-开放地址法和链地址法的实现

来源:互联网 发布:用户画像 大数据知乎 编辑:程序博客网 时间:2024/06/15 06:23

基本定义

散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系 f,使得每个关键字key对应一个存储位置f(key)。这种对应关系f称为散列或哈希函数。采用上述思想将数据存储在一块连续的存储空间中,这块连续的存储空间称为散列或哈希表。关键字对应的存储位置称为散列地址。散列技术最适合的求解问题是查找与给定值相等的记录。
如果碰到两个不同的关键字key1key2,但却有相同的f(key1)=f(key2),这种现象称为冲突,并把key1key2 称为这个散列函数的同义词(synonym)。

散列函数构造方法

好的散列函数参考如下两个原则:

  • 计算简单
  • 散列地址分布均匀

最常用的方法是除留余数法,对于散列表长度为m的散列函数是 f(key)=key mod p (pm)

处理散列冲突

处理散列冲突的常用方法有两种,一种是开放地址法,一种是链地址法。

开放地址法

开放地址法就是一旦发生冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列表总能找到,并存入。开放地址法又分为线性探测法,二次探测法和随机探测法。
线性探测法的公式是:
fi(key)=(f(key)+di) MOD m (di=123m1)
二次探测法目的是为了不让关键字都聚集在某一区域,公式为:
fi(key)=(f(key)+di) MOD m (di=12122222q2q2qm1)

链地址法

将所有同义词的关键字存储在同一个单链表中,称这个单链表为同义词子表,在散列表中只存储同义词子表的头指针。只要有冲突,就在同义词的子表中增加结点。

开放地址的代码实现

#include <stdio.h>#include <stdlib.h>#define MaxSize 100 // 存储空间初始分配大小#define HashSize 12 //哈希表数组的长度#define NULLKEY -32768  //哈希表数组初始值typedef struct{    int *elem ;  // 数据元素存储基址,动态分配数组    int count;   // 当前元素的个数}HashTable;int m = 0;  // 哈希表表长void InitHashTable(HashTable *Hash){    m = HashSize;    Hash->count = m;    Hash->elem = (int *)malloc(m * sizeof(int));    for(int i = 0; i < m; i++)        Hash->elem[i] = NULLKEY;}int Hash_fuction(int key){    return key % m;  //除留余数法}void InsertHash(HashTable *Hash, int key){    int addr = Hash_fuction(key); //求哈希地址    //如果不为空,则冲突    while(Hash->elem[addr] != NULLKEY)    {        addr = (addr + 1) % m; // 开放定址法的线性探测    }    Hash->elem[addr] = key;}int SearchHash(HashTable *Hash, int key, int *addr){    int tmp = Hash_fuction(key);    *addr = Hash_fuction(key);    //如果不相等,则冲突    while(Hash->elem[*addr] != key)    {        *addr = (*addr + 1) % m;        //如果继续查找为空或回到原点,则关键字不存在        if(Hash->elem[*addr] == NULLKEY || *addr == Hash_fuction(key))            return false;    }    return true;}int main(int argc, char const *argv[]){    int arr[HashSize]={12,67,56,16,25,37,22,29,15,47,48,34};    HashTable Hash;    InitHashTable(&Hash);    for(int i = 0; i < m; i ++)    {        InsertHash(&Hash, arr[i]);    }    int addr;    int key = 56;    int result = SearchHash(&Hash, key, &addr);    if(result)        printf("值为%d在哈希表的地址为:%d\n", key, addr);    else        printf("关键字不存在\n");    key = 10;    result = SearchHash(&Hash, key, &addr);    if(result)        printf("值为%d在哈希表的地址为:%d\n", key, addr);    else        printf("关键字不存在\n");    for(int i = 0; i < m; i ++)    {        key = arr[i];        result = SearchHash(&Hash, key, &addr);        if(result)            printf("值为%d在哈希表的地址为:%d\n", key, addr);        else            printf("关键字不存在\n");    }    return 0;}

运行结果是:

值为56在哈希表的地址为:8关键字不存在值为12在哈希表的地址为:0值为67在哈希表的地址为:7值为56在哈希表的地址为:8值为16在哈希表的地址为:4值为25在哈希表的地址为:1值为37在哈希表的地址为:2值为22在哈希表的地址为:10值为29在哈希表的地址为:5值为15在哈希表的地址为:3值为47在哈希表的地址为:11值为48在哈希表的地址为:6值为34在哈希表的地址为:9

链地址的代码实现

哈希表的C实现(一) - 红心李 - 博客园
http://www.cnblogs.com/xiekeli/archive/2012/01/13/2321207.html

哈希表的C实现(二) - 红心李 - 博客园
http://www.cnblogs.com/xiekeli/archive/2012/01/16/2323391.html

哈希表的C实现(三)—传说中的暴雪版 - 红心李 - 博客园
http://www.cnblogs.com/xiekeli/archive/2012/01/17/2324433.html

哈希表的链地址法实现和哈希桶实现_程式設計
http://lubia.cn/hashing-bucket-implementation

散列表(二):冲突处理的方法之链地址法的实现(哈希查找) - Meditation - 博客频道 - CSDN.NET
http://blog.csdn.net/jnu_simba/article/details/9632675

0 0