zoukankan      html  css  js  c++  java
  • 【经典数据结构】哈希表

    哈希表的基本概念

      哈希表,也叫散列表,它是基于快速存取的角度设计的,是一种典型的“空间换时间”的做法。哈希表是普通数组的一种推广,因为数组可以直接寻址,故可在O(1)时间内访问数组的任意元素,其中它的插入和删除的时间复杂度也是O(1)。

      哈希表是根据关键字(Key Value)而直接进行访问的数据结构。也就是说,它将关键字通过某种规则映射到数组中的某个位置,以加快查找的速度。这个映射规则称为哈希函数(散列函数),存放记录的数组称为哈希表。哈希表建立了关键字和存储地址之间的一种直接映射关系。

      若多个不同的关键字通过哈希函数计算得到相同的数组下标,称其发生了冲突,这些发生冲突的不同关键字称为同义词。一方面,设计好的HASH函数应尽量减少这这样的冲突;另一方面,由于这样的冲突总是不可避免的,所以还要设计好处理冲突的方法。

    哈希函数

      所有散列都有如下一个基本特性:如果两个散列值是不相同的(根据同一函数),那么这两个散列值的原始输入也是不相同的(根据同一函数)。那么这两个散列值的原始输入也是不相同的。这个特性使散列函数具有确定性的结果,具有这种性质的散列函数称为单向散列函数。

      典型的散列函数都有无限定义域,比如任意长度的字节字符串,和有限的值域,比如固定的比特串。

       

    常用哈希函数

      我们在数据结构这门课程,曾经学习这几种简单常用的散列函数,如直接定址法、乘法散列法、除法散列法、除留余数法,折叠法等。

      以下我们介绍工业界比较著名的哈希函数(哈希算法),这些算法通常应用于信息安全领域)。

      典型的哈希算法包括MD4,MD5和SHA-1,MD5和SHA-1(安全哈希算法)可以说是目前应用最为广泛的Hash算法,而它们都是以MD4为基础设计的。

    处理冲突的方法

      任何哈希函数都不可能绝对地避免冲突,为此必须考虑冲突发生时应如何进行处理,即为产生冲突的关键字寻找下一个“空”的Hash地址,于是提出了处理冲突的各种方法。

      1) 链地址法

        链地址法是指把散列在同一槽的所有元素(同义词)都存储在一个线性链表中,这个链表由其散列地址唯一标识。

        给定一个能存放n个元素的、具有m个槽位的散列表T,定义T的装载因子(load factor)α为n/m,即一个链的平均存储元素数。α可以小于、等于或者大于1

      2)开放定址法

        开放定址法是指可存放新表项的空闲地址。既向它的同义词表项开放,又向它的非同义词表项开放。其数学递推公式为(Hi表示冲突发生后第i次探测的散列地址):

              Hi=(H(key)+di)%m

    式中,i=1,2,...,k(k<=m-1),m为散列表表长,di为增量序列,di通常有以下几种取法:

      当di=1,2,..,m-1时称为线性探测法。其特点是,冲突发生时顺序查看表中下一个单元,直到找出一个空单元或查遍全表。

      当di=12,-12,22,-22,...,k2,-k2时,其中k<=m/2,又为二次探测法。

      当di是伪随机序列时,称为伪随机探测法。

      3)再散列法

      当冲突发生时,利用另一个哈希函数再次计算一个地址,直到冲突不再发生,这种方法称为再哈希法。

      4)建立一个公共溢出区

      一旦由哈希函数得到的地址冲突,就都填入溢出表。

      有以下两点需要说明: 

      1)在开放定址的情形下,不能随便删除表中已有的元素,因为若删除元素将会截断其他具有相同散列地址的元素的查找地址。所以若想删除一个元素时,给它做一个删除标记,进行逻辑删除。但这样做的副作用是,在执行多次删除后,表面上看起来散列表很满,实际上有许多位置没有利用,因此需要定期维护散列表,要把做删除标记的元素物理删除。

      2)计算查找的平均查找长度ASL时,平均的概念是对表终当前非空元素而言的,并非是整个表长。计算查找失败的平均查找长度ASL时,平均的概念是针对表长。

    链地址方法和开放定址法的区别

      1. 链地址法的节点是动态申请的,所以适用于无法确定建表前无法确定表长的情况;链地址法的指针需要空间,故当结点规模较小时,开放定址法较为节省空间

      2. 拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短

      3. 开放定址法为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间。而拉链法中可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;

    哈希算法是否可以用来加密?

    解答:哈希(hash)就是把任意长度的输入通过哈希算法,变换成固定长度的输出,该输出就是哈希值(散列值)。这种转换是一种压缩映射,使得散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一确定输入值。哈希算法是一种消息摘要uanfa,虽然哈希算法不是一种加密算法,但由于其单向运算,具有一定的不可逆性使其成为加密算法中的一个重要构成部分。

    一致性哈希:http://blog.codinglabs.org/articles/consistent-hashing.html

    参考资料:

      1. 《数据结构与算法分析c++描述》 第三版  人民邮电出版社

  • 相关阅读:
    【体验】在Adobe After Effects CC 2018中使用脚本创建窗口
    flask中错误使用flask.redirect('/path')导致的框架奇怪错误
    01-复杂度2 Maximum Subsequence Sum
    01-复杂度1 最大子列和问题
    02-线性结构1 两个有序链表序列的合并
    bfs—迷宫问题—poj3984
    bfs—Dungeon Master—poj2251
    bfs—Catch That Cow—poj3278
    GPTL—练习集—006树的遍历
    DB2存储过程——参数详解
  • 原文地址:https://www.cnblogs.com/vincently/p/4743891.html
Copyright © 2011-2022 走看看