• 哈希表


      今天是7.20,是计划的截止日期。前几天一直在玩滑板拖着没写博客没学习,今天下午又学习了一遍哈希表的知识,按计划该写博文完成哈希表的学习。

      哈希表(hash table)又称为散列表,是一种对实体进行索引的数据结构。它的特点是查询速度快,一个拥有好的哈希函数的哈希表,进行查找时可以实现均摊常量时间O(1)的时间复杂度,这无疑是很快速的查找速度。比方说,数组本身就是最简单的一种哈希表,根据数组下标可以快速找到下标对应的数组元素。

      对于哈希表,根据解决冲突的形式不同,有开散列和闭散列两种形式。这里的“开、闭”可以形象地认为是,主表状态是发散(开散列)的还是一维线性结构(闭散列)。

      有了对哈希表的大概了解,下面再详细介绍一下哈希表的基本组成部分。

      首先,哈希表由键-值组成(key-value)。键是实体被索引时的标识符,值是被索引的实体。举下面一个例子对键和值进行说明:

      《红楼梦》 ————>  文学类,

    在以上的例子中,文学类即是键,而《红楼梦》则是值。一般使用数组元素存储值,使用数组下标表示键。

      其次,由值转化为键的过程,需要使用哈希函数,哈希函数是一种将值映射到键的规则与方法。哈希函数可以理解为值与键的对应关系。输入一个值,根据哈希函数,可以求得一个对应的键。一个好的哈希函数,会让将不同的值尽可能映射成不同的键。举下面一个例子对哈希函数进行说明:

      已知值:apple、bed、egg;

      已知哈希函数:根据实体首字母,将a对应1,将b对应2,以此类推……;

      那么组成的哈希表如下:

    键(数组下标) 0 1 2 3 4 5
    值(实体) NULL apple bed NULL NULL egg

      当然上面这个哈希函数并不好,因为很明显以a开头的单词多了去了,此时如果仍旧使用这个哈希函数,将导致大量冲突的产生,关于冲突的解决我们在第三部分讲解。常用的哈希函数一般会这么操作:首先将值映射到一个整数,再通过对一个大质数取模来映射到一定范围内的整数。举下面一个例子进行说明:

      cba ————> 2 * 260 + 1 * 261 + 0 * 262 = 28,

    28 % 1000007 = 28,

    经过这两步,就完成了一个将值映射到键的操作。

      第三,在第二部分我们简单介绍了冲突的情况,也就是不同的值恰好被映射到同一个键时怎么办。在这个部分,我们来探究如何解决冲突。解决冲突一般而言有两种办法:开散列、闭散列,这两个概念在第一部分提到过。

      开散列,是使用链表来存储每一个键对应的所有的值,值得注意的是,此时主表用来存储链表头而不存储具体的值。这是一种类似邻接表的结构,也可以使用数组模拟链表。

      闭散列,是对冲突的键按规则存储值存储的下标,主表可以直接存储具体的值,并且每个下标只能存储一个。还需要一个探测函数,当不同的值发生冲突时,使用探测函数查找下一个值,一个好的探测函数可以尽快解决冲突。最简单的探测函数如下:

      ① h(p) = p + 1 (p < k)

        ② h(p) = 0 (p = k)。

      闭散列相对于开散列,简单直接,不需要实现链表。但是也有其自身的缺点,比如说会增加整体冲突的概率,并且需要用标记删除来代替真正的删除。

      最后,谈一下哈希表的常见运用,如下:

    1. 模拟映射关系,比如说DNS解析,就是将网址映射到IP地址。
    2. 防止重复。
    3. 缓存/记住数据。

      

      

  • 相关阅读:
    201771010111 李瑞红 《第十二周学习总结》
    201771010111李瑞红《第十一周学习总结》
    李瑞红201771010111第十周 学习总结
    李瑞红201771010111《第九周学习总结》
    201771010111李瑞红《面向对象的程序设计》第八周实验总结
    2017710101111李瑞红《第七周学习总结》
    李瑞红201771010111《第六周学习总结》
    李瑞红201771010111《面向对象程序设计(java)》第四周学习总结
    201771010113 李婷华《面向对象程序设计(Java)》第十二周总结
    201771010113 李婷华 《面向对象程序设计(Java)》第十一周总结
  • 原文地址:https://www.cnblogs.com/potapo/p/9343457.html
Copyright © 2020-2023  润新知