哈希排序

来源:互联网 发布:软件怎么发布 编辑:程序博客网 时间:2024/05/02 05:09

转自:http://df22b.blog.163.com/blog/static/2488576520119110577610/

哈希排序常在海量数据中查找数据非常有用。

  先看一道题:搜索引擎会通过日志文件将用户每次检索使用的所有记录全部记录下来,每个查询串的长度是1-255个字节。

假设现在有1000万个记录(因为有重复的,所以实际上只有大概300万种左右),一个查询串的查询次数越多,说明查询他的用户越多。现在在这1000万个记录中取出前10个最热门的查询串,要求内存使用不超过1G.

  求出前10个的步骤是:首先要统计每个记录出现的次数,然后排序,输出前10个就好。因此这个程序设计问题要分2步来完成。

一.统计每个记录的出现次数

   最先想到是方法就是申请一个数组,将每个访问到的记录名放到数组中,并放入他的访问次数。那么我们不知道这个记录到底有多少个,所以不好确定数组大小。然后就是1000万条记录,每个最坏情况下255字节,需要使用内存为2.55G内存,题中明显要求内存使用不大于1G.

   根据上述方法的缺点,我们就想到是不是可以先通过外部排序对1000万个记录先排序,然后统计每个记录出现的次数。但是外部排序的实践复杂度为       O(NlogN),而且统计系数还要遍历一遍,O(N),还有就是要频繁访问文件,也就是频繁使用I/O。系统速度明显会下降。

   那么有没有什么办法,既可以实现排序,又不需要使用太多内存呢。答案是哈希表。

对每个字串我们哈希出一个值,而这个值若存在于哈希表中,则表中对应项的值加一。否则,在表中添加这个项,并将这个项的值设为1.这样当我们遍历一次1000万个记录后,就统计完了每个记录的次数。由于访问哈希表的时间复杂度为O(1),遍历一遍所有记录为O(N),所以实践复杂度比外部排序要好很多,而且我们不需要分批的一次次的使用I/O访问文件。

二.找出前10个最热门的记录

  普通排序:经过第一步骤的统计之后,大概只剩300万条记录,1G的内存还是可以放下的。这里可以使用任何普通排序将其排序,然后取前10;由于排序元素较多,所有采用O(NLogN)的排序算法进行排序(归并,快速)。

 部分排序:生成一个10个元素大小的数组。对数组进行初始化,数组元素按降序排列。遍历300万个元素,每次找到比数组最后一个元素大的数就进行替换,然后对10个元素的数组排序,由于只有10个元素,所有排序很快。当遍历完300万个元素后,输出数组中的10个元素就好。对10个数组的排序算法,可采用选择,插入,希尔排序等,实践复杂度为O(n2/2),所以实践复杂度为O(N*10^2/2).相比上一个普通排序,时间复杂度已经好了不少。

  在部分排序中,明显的对10个元素的数据结构,每次遍历后,若是替换数组元素,然后进行排序时数据交换是比较频繁的,那么有没有不需要频繁交换数据的数据结构。答案是堆。我们可以申请10个元素的堆,堆排序的时间复杂度为O(n),也不需要频繁交换数据。