高效算法(散列,排序)

时间:2013-09-29 00:52:08

标签: java algorithm sorting hashmap

我遇到了以下问题 - 我收到一个文本文件,其中包含大量允许重复的单词。我需要编写一个算法,输出那些出现频率最高的1000个单词。这是一个例子

**input.txt**

aa aa bb cc bb bb bb dd dd

**output.txt** (note - frequencies can be repeated)

bb 4
aa 2
dd 2
cc 1
  1. 这是我解决这个问题的方法。首先阅读所有单词并将其存储在HashMap中,并将单词作为键。这样做的最终结果是我的所有单词都有它们的频率。

  2. 现在我遍历HashMap并为每个键值对创建一个对象{word,frequency},然后将其插入SortedSet(我为此编写了一个比较器)

  3. 现在我只需迭代SortedSet 1000次以获得结果。

  4. 我想知道解决这个问题的更好方法。

    由于

2 个答案:

答案 0 :(得分:4)

  

有没有更好的方法来解决这个问题?

有两种方法可以看待这个......取决于你对“更好”的意思。

如果“更好”意味着“使用更少的时间和/或内存”,那么有可能解决此问题,具体取决于问题的大小和您可以使用的资源。例如:

  • 如果文本文件(或多个文件)足够大以证明这一点,您可以考虑将问题分区为在多处理器上运行。但这不是直截了当的......如果问题太小,分区的开销实际上会使解决方案变慢!

  • 链接的Q& A描述了一种可能加快您的步骤2和3的方法。问题是,如果您对代码进行基准测试,您可能会发现第1步是花费大部分CPU时间的地方。 (输入文件越大,效果就越明显......)

如果“更好”意味着“更快地解决问题”,那么答案就是“可能没有”。假设您已经实现了所描述的算法的良好实现版本,那么采用更加复杂的算法(可能)更快的努力可能并不值得。

计算机时间比软件开发人员时间便宜!


我的建议是做以下事情:

  1. 对现有计划进行基准测试。在真实的输入文件上运行得足够快吗?如果“是”,请调用程序完成。

  2. 配置在现实输入文件上运行的现有程序。分析是否显示任何明显的性能热点?有代码调整的机会吗?如果“是”尝试,请重复基准测试步骤,看看他们是否确实有所帮助。

  3. 查看GC日志。是否有迹象表明您的代码有过多的GC开销?如果“是”,请查看是否有一些简单的GC调整(如增加堆大小)会产生影响。

  4. 如果在上述所有情况之后仍然没有达到可接受的性能,那么现在是时候开始寻找替代算法了。

答案 1 :(得分:2)

让我们关注第2步和第3步。假设有N个单词,每个单词都有一个给定的频率,你必须找到前K(在你的情况下为1000)。

您的方法在O(N log N)中运行。斯蒂芬提到,这已经足够了:)无论如何,这里有一些可能的改进。

第一种方法:正如链接中所建议的那样,您可以使用最小堆(您可以使用优先级队列)来维护前1000名。实现起来并不难。获得具有频率的地图后,开始迭代它。如果最小堆的大小小于K,则继续推动该对(字,频率)。如果堆的大小为K,则将当前条目的频率与映射到堆的根(堆中的最低频率)进行比较。如果新频率较低,请忽略它。如果它更高,则从堆中弹出最低值并推送当前值。这种方法将在O(N log K)中运行。

第二种方法: selection algorithm在O(N)中找到列表(未排序)中的第K个最大(或最小)数字。您可以找到最大的K_th,然后迭代地图以获得小于或等于K的所有内容。如果大于K,则必须是第K_th个最大数字重复多次的情况。如果你跟踪它,你可以删除这个数字所需的数量来获得前K.这将需要O(N)。

第三种方法:你可以做一个随机快速排序的变种来找到前K.我认为,预期的运行时间是O(N)。