【数据结构】哈希表

【数据结构】哈希表

定义

  • 哈希表(Hash table,也叫散列表),是根据关键字值Key直接进行访问的数据结构,他通过把关键字值映射到表中一个位置(数组下标)来直接访问,以加快查找关键字值的速度。

  • 这个映射函数叫做哈希(散列)函数,存放记录的数组叫做哈希表

  • 给定表M,存在函数f(key),对任意的关键字值key进行映射操作,代入函数后若能得到包含该关键字的表中地址,称表M为哈希表,函数f(key)为哈希函数。


最简单的哈希——字符哈希

int main() {
    //求字符串s中各个字符出现的次数
    string s[] = "sadqweasdqweasdqwe";

    //哈希表    
    int hash_table[26] = {0};

    for(int i = 0;i < s.size();i++) {
        //哈希转换
        int key = s[i] - 'a';
        //通过key直接访问、修改value
        hash_table[key]++;
    }

    return 0;
}

遇到以下问题时如何进行哈希转换呢👇

  1. 负数或者非常大的数,如-5,9999999999999,…
  2. 字符串,如abcde、XYZ、…
  3. 浮点数、数组、对象、…

解决
利用哈希函数,将关键字值(key)(大整数、负数、字符串、浮点数、…)转换为整数再对表长取余,从而关键字值被转换为哈希表表长范围内的整数。

哈希冲突

由于哈希算法被计算的数据是无限的,而计算后的结果范围(哈希表表长)有限,因此总会存在不同的数据经过计算后得到的值相同,这就是哈希冲突

比如:
77 % 7 = 0,21 % 7 = 0,77和21经过哈希转换后的关键字均为0,此时就发生了冲突。

解决方法

哈希冲突解决方法有:

  1. 链地址法(拉链法)
  2. 开放地址法
  3. 再哈希法
  4. 创建公共溢出区

Tips:如果使用取余作为哈希转换算法,应尽量设置表长为素数,这样转换出来的key会尽量平均,从根源上减少哈希冲突

这里重点介绍其中的一种——链地址法(拉链法)
将所有哈希函数结果相同的结点链接在同一个单链表中(如下图👇)

若选定的哈希表长度为m,则可将哈希表定义为一个长度为m的指针数组t[0 ,…, m - 1],指针数组中的每个指针指向哈希函数结果相同的单链表。

插入value
将元素value插入哈希表,若元素的value的哈希函数值为hashkey,将value对应的节点以头插法的方式插入到以t[hashkey]为头指针的单链表中。
查找value
若元素value的哈希函数值为hashkey,遍历以t[hashkey]为头指针的单链表,遍历查找链表各个节点的值是否为value
在这里插入图片描述
开放定址法
从发生冲突的那个单元起,按照一定的次序,从哈希表中找到一个空闲的单元。然后把发生冲突的元素存入到该单元的一种方法。开放定址法需要的表长度要大于等于所需要存放的元素。在开放定址法中解决冲突的方法有:线行探查法、平方探查法、双散列函数探查法。开放定址法的缺点在于删除元素的时候不能真的删除,否则会引起查找错误,只能做一个特殊标记。只到有下个元素插入才能真正删除该元素。

再哈希法
就是同时构造多个不同的哈希函数

创建公共溢出区
将哈希表分为公共表和溢出表,当溢出发生时,将所有溢出数据统一放到溢出区。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值