美丽的Hash

来源:互联网 发布:劳伦斯许 知乎 编辑:程序博客网 时间:2024/05/16 23:40
提到Hash,大家都会想到它的“快速存取”,在O(1)时间复杂度里就可以查找到目标元素,或者判断其是否存在,基于Hash我们有HashTableHashMap等多种数据结构。Hash数据结构里的数据对外是杂乱无序的,我们无法得知其具体存储位置,也不知道各个存储元素位置之间的相互关系,但是我们却可以在常数时间里判断元素位置及存在与否,这不能不说是一个神奇,而这个神奇的创建在数学上却是那么的简单,不过是一个根据不同输入内容产生随机数的一个函数而已。关于Hash函数,我们在这里不做过多讨论,我们在这里讨论一下Hash的特殊妙用。

Hash有以下几个功能:

1、 快速存取(这对于一个集合来说无疑是最适合的)

2、 统计某些数据(这是基于功能1HashMap数据结构)

3、 将大量数据进行分类(对于同一个输入,得到的Hash值相同)

本篇我们将对其进行探讨,请看下面实例:

1、 有两个字符串str1str2,要求输出在两个字符串中都出现的字符,且依照str1中字符出现次序输出。

我们只要将str2中的字符依次存入一个HashTable,然后依次扫描str1中字符ch,如果chHashTable中,那么输出ch,否则扫描下一个字符。

2、        10个文件,每个文件1G,每个文件的每一行都存放的是用户的query,每个文件的query都可能重复。如何按照query的频度排序?

普通思路就是创建一个HashMap<pair<query, count>>依次扫描十个文件,统计每一个query出现的次数,然后对该HashMap中的数据进行排序,但是由于文件的大小超过10G,所以统计后的结果HashMap大小可能太大,以至于内存中难以存储。

在这里,我们可以将10个文件内的数据重新划分一下,划分依据:

                fileNo=Hash(query) % 100 …… (1)

只有fileNo相同的 元素才被放进同一个文件,假设文件名用相应的”fileNo.data”来命名,那么文件”fileNo.data”中的元素经过hash函数 (1)得到的值都相同都为fileNo而且同一个query的所有记录都会在同一个文件中出现。这样我们只要对新得到的100个文件进行统计和排序,将得到的结果写入相应的磁盘文件,然后对得到的100个结果文件进行归并排序即可。

3、 从海量数据中获取访问百度次数最多的IP地址。

如果直接对海量数据使用HashMap进行统计,同样会遭遇内存不足的难题,可以仿照例2的方法,将储存有海量数据的文件HashN(=1024)个文件,N的取值要满足:

                Size of memory > size of data / N

然后对得到的N个文件使用HashMap分别进行统计,并且取得每个文件中访问百度次数最多的IP,可以得到N<IP, count>,然后从这N<IP,count>中取得count最大的IP,这便是所有数据中访问百度次数的IP

通过讨论,我们已经看到Hash的巧妙,但是Hash也不应该滥用,因为储存相同的数据使用Hash数据结构占用内存要比其他数据结构多许多,所以在分析问题时要视情况而定。

我的另一篇文章“海量日志数据,提取出某日访问百度次数最多的那个IP。”就是这个例子。

原创粉丝点击