我需要创建一个计算文本中每个单词频率的程序,另外我需要能够返回 n 的列表(通常是单词)(如果更多单词具有相同的频率,它们按字母顺序排序)。还有一个不计算的单词列表(停用词)。
总体来说哪种方法更有效?
P.S。 @Moderators我知道有一个类似的question,但我有一个不同的约束,需要不同的结构。
答案 0 :(得分:2)
我们假设总共有k
个单词和m
个不同的单词,您希望n
最常用的单词。
<强> TreeMap的强>
由于地图中永远不会超过m
个字词,因此每次更新/插入操作都需O(log m)
,总运行时间为O(k log m)
。
<强> HashMap中强>
每次更新/插入都需要花费O(1)
的费用,所有字词都会O(k)
。
然后,由于地图中会有m
个字词,因此排序将采用O(m log m)
。
但我们可以做得比排序更好 - 我们可以遍历HashMap
并维护n
(heap)n
最常用的字词(主要按以下排序)频率,其次是字母顺序)。每次插入堆后,如果大小大于O(m log n)
,我们删除最不频繁的单词。这将采用O(k + m log n)
。
因此,预计总运行时间为n <= m
。
<强>比较强>
自m <= k
和m log n <= k log m
以来,我们知道n
,并且假设有大量重复项或m
略小于k + m log n <= k log m
,{ {1}},因此HashMap
通常是首选选项。
答案 1 :(得分:0)
停用词:HashSet或regexp。
我会使用哈希映射来计算频率计数:
所以你会做很多插入。 HashMap的总体插入成本: O(n),对于TreeMap: O(n log w)。
对哈希映射的成本进行排序: O(w log w),以及提取开销 O(w)。即使TreeMap为零, O(w log w)对于大型 n 也会变得非常小。
请注意,一般情况下,如果不对两者进行基准测试,都无法保证解决这个问题。
答案 2 :(得分:0)
您可以对最终HashMap<String, Integer>
个计数/单词执行一次传递,并使用TreeMap<Integer, List<String>>
和TreeMap.firstKey()
和TreeMap.size()
方法计算前N个单词。练习留给读者。或者(或更好),使用像this one这样的红黑树,当您发现较大的计数时(当您的前N中树的大小> N时),您不断修剪最低计数节点。