C/C++算法——散列表

1、散列表介绍

  • 散列表的英文叫Hash Table,我们平时也叫它哈希表或者Hash 表。散列表用的是数组支持按照下标随机访问数据 的特性,所以散列表其实就是数组的一种扩展 ,由数组演化而来。可以说,如果没有数组,就没有散列表。

  • 散列表是算法在时间和空间上作出权衡的例子,它介于两个极端之间:

    • 如果没有内存限制 ,我们可以直接将键作为一个(可能非常庞大)数组索引,那么查找操作只需要一次
    • 如果没有时间限制,我们可以使用无序数组并进行顺序查找,这样就只需要很少的内存。
  • 使用散列的查找算法分为两步。

    • 第一步是用散列函数 将被查找的键转化为数组的一个索引(可能出现哈希碰撞,即不同的键可以转化为相同的索引值)
    • 第二步是处理碰撞冲突的过程。有两种常用的解决方法:拉链法线性探测法(开放寻址法的一种)

2、散列函数

  • 散列函数的定义
    • 一个把查找表中的关键字映射成该关键字对应的地址的函数,记为 Hash(key)=Addr(这里的地址可以是数组下标、索引或内存地址等)。
  • 散列函数的构造方法
    • 直接定址法

      直接取关键字的某个线性函数值为散列地址,散列函数为:H(key)=keyH(key)=a*key±b。式中,ab 是常数。这种计算方法简单且不会发生冲突。但只适合关键字的分布基本连续的情况。

    • 除留余数法

      这是一种同样简单、最常用的方法,假定散列表表长为m,取一个不大于m但最接近或等于m的质数p,散列函数为:H(key)=key%pH(key)=key MOD pMOD是取模运算符)模p为最接近m的质数时造成冲突的可能性最小。

    • 数字分析法

      比如学号一个班的同学前几位都是2022030XX,后两位每种数码(0,1,2...)出现的机会均等,此时应选取数码分布较为均匀的若干位作为散列地址。该方法适合于已知关键字集合,若更换了关键字(身份号),则需要重新构造新的散列函数。

    • 其他

      • 浮点数:例如将键转换为二进制再使用除留余数法。
      • 字符串:例如将键转换为大整数(例如把字符串当作N位的R进制值),然后再使用除留余数法。
      • 组合键。
      • 自定义的hashCode方法。
      • ...

3、哈希碰撞的处理

  • 基于拉链法的散列表
    散列表中,每个桶(bucket)或者槽(slot)会对应一条链表,所有散列值相同的元素我们都放到相同槽位对应的链表中:

  • 线性探测(Linear Probing)
    • 插入:如果某个数据经过散列函数散列之后,存储位置已经被占用了,我们就从当前位置开始,依次往后查找,看是否有空闲位置,直到找到为止。

    • 查找 :过程和插入一样,找到对应数组下标后,对比x与数组中存储的值是否相等,若不等则依次往后查找...

    • 删除 :删除的元素,特殊标记为 deleted。当线性探测查找的时候,遇到标记为 deleted 的空间,并不是停下来,而是继续往下探测。

4、参考文献

  1. 数据结构☞散列表
  2. 散列(Hash)表
  3. 算法(第四版) 3.4散列表
相关推荐
暗然而日章2 分钟前
C++基础:Stanford CS106L学习笔记 9 类模板(Class Templates)
c++·笔记·学习
mywyu_wmb5 分钟前
编译CEF 132.3.3
c语言
小年糕是糕手10 分钟前
【C++同步练习】类和对象(三)
开发语言·jvm·c++·程序人生·考研·算法·改行学it
Learner__Q12 分钟前
每天五分钟:leetcode动态规划-递归与递推_day2
算法·深度优先
wadesir14 分钟前
Judy数组:C语言中的高性能动态数组(全面入门Judy库使用指南)
c语言·开发语言
代码游侠15 分钟前
学习笔记——Linux内核链表
linux·运维·笔记·学习·算法·链表
Fcy64816 分钟前
C++ set和multiset的使用
开发语言·c++·stl·map·multimap
八个程序员16 分钟前
c++常见问题1——跳出代码
开发语言·c++
一个平凡而乐于分享的小比特17 分钟前
C语言中 volatile 关键字总结
c语言·volatile
初晴や17 分钟前
第一章:计算机基础知识
c++·计算机基础知识、