散列Hashtable的故事

前因:

  hashtable是数据结构里面很重要的一个概念,之前很长很长的时间内,都有多次听到过这个概念,因此曾经也有过去查资料有一些了解,但对hashtable这个概念还是不甚清晰。今天又看到了hashtable方面的视屏讲解,加上本人之前对MD5类似的散列加密算法的简单学习中的一个特性的了解,然后就有了一点点自身对hashtable这种数据结构的理解。

之前的hashtable学习的一些过程中的一些概念

  容器:hash是一个存放数据的容器,这些数据是一些无序的数据,例如一堆散乱的整数(1,333,566,7342,6565,3342,25,34242,436,657,879,6589,6,8,654,69,9045...),这些东西经过取余的运算放在一个容器中(不得不说取余是个很重要的概念,但也是因为这个让我一直对hashtable困惑不解)。

  篮子bucket:hashtable的一个很重要的概念,hashtable是有一个个篮子组成,篮子里面不能存放相同的数据,这就是hashtable的特性。

  如果有相同的数据的处理办法:因为上面提到hashtable里面的数据经过取余得到,然而经过取余很容易产生两个相同的数据,例如10001%10 == 100000001%10(这里的10是bucket_size),产生相同的数据的处理办法就是将hashtable的bucket里面存放一个链表,相同的数据追加在链表上。

那天在学习密码学中的散列加密算法后产生的一些认识(因为这个上面所说的有一个共同点就是hash算法,这个也是今天的主要理解):

  MD5加密:不同长度的字符序列通过MD5加密后产生128bit的01序列,即就是32一个字节。这里面很重要的东西就是那个加密过程,他使用了一种hash算法,然后使不同长度的字符序列通通变成128bit,即使是一个字符‘a’,经过hash算法后也成了128bit,而一个字符串“aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa”经过hash算法后成了128bit(这个字符串明显比128bit(32字节)大很多),这就很有意思。

那么接下来说本次又接触hashtable后的理解:

  ①上面说明了MD5加密产生128bit数据,128bit如果关联到hashtable中是什么东西?其实2128 == bucket_size。这就有点惊人了,bucket_size竟然这么大,有对了bucket_size这个概念的理解,那么我们就知道MD5为什么要128bit了,这是为了安全考虑喽。如果MD5最后产生的bucket_size很小(例如8bit,28 = 256),那么如果有257个不同的字符串都使用MD5加密,那么势必会产生两个相同的加密结果,那么它应该就不会被称为MD5了,因为这太不安全(当然MD5不仅仅依靠128bit的长度来变得相对安全,他的算法的数学背景知识更为重要)。这里考虑一种极端结果,当有2128+1一个不同的字符串时,那么经过MD5的hash后也会产生至少两个相同的字符串。

  ②通过MD5的bucket_size我对hashtable的重新理解:hashtable最为核心的部分其实就是hash算法(在c++中称为hash function),上面所说的取余其实就是一种hash算法(因为这种hash算法太过于简单,因此自学hashtable时给我造成了很大的困扰)。在c++中我们可以用一个很常用的容器vector来表示hashtable(vector_size == bucket_size),这就已经可以表示为一个hashtable了。这个我想说明的是,构造一个hashtable很简单,它无非就是一种容器,甚至我们可以用一个list来表示hashtable。但是重要的是,当我们有一堆无序混乱的数据时(甚至这堆数据可能不是一种类型),我们怎么存放在hashtable中(即vector中)?hash function就特别重要,例如上面提到的MD5的hash function竟然可以几乎将任意长度的字符串生成一个128bit的字符串。无序混乱的数字经过hash function后变成了固定长度的128bit(c++程序中一般比这小,因为在c++中hashtable所用的vector是慢慢增长起来的,采用二倍附近找质数的方式增长),这很让人惊喜,所以再次强调hash function的重要性(或许这个hash function的实现并不难,但是这个概念很重要)。

  ③最后c++中用hashtable作为底部支撑实现了unorder_set,unorder_map等数据结构,它在实现时的底部用到vector数据结构来做那个bucket,使用hashtable支撑的容器最重要的就是传入那个hash function(函数对象或称仿函数)。

猜你喜欢

转载自www.cnblogs.com/Ccluck-tian/p/11930365.html