我希望在性能关键代码中多次计算熵和互信息。作为中间步骤,我需要计算每个值的出现次数。例如:
uint[] myArray = [1,1,2,1,4,5,2];
uint[] occurrences = countOccurrences(myArray);
// Occurrences == [3, 2, 1, 1] or some permutation of that.
// 3 occurrences of 1, 2 occurrences of 2, one each of 4 and 5.
当然,显而易见的方法是使用关联数组或使用“标准”排序算法(如快速排序)对输入数组进行排序。对于小整数,如字节,代码目前专门用于使用普通的旧数组。
是否有任何聪明的算法比哈希表或“标准”排序算法更有效地执行此操作,例如非常有利于插入更新的关联数组实现,或者当数据具有很多关系?
注意:非稀疏整数只是可能数据类型的一个示例。我想在这里实现一个合理的通用解决方案,但由于只包含整数的整数和结构是常见的情况,如果它们非常有效,我会对这些特定的解决方案感兴趣。
答案 0 :(得分:3)
除了对一些代表您期望遇到的实际工作量的案例进行基准测试之外,没有什么好方法可以解决这些问题(显然存在风险,您可能会选择实际上恰好是的样本)有偏见/无代表性 - 如果您正在尝试构建一个将由您控制之外的许多外部用户使用的库,则风险不小。)
答案 1 :(得分:2)
请详细说明您的数据。
无论如何,我建议采用以下思路:修改mergesort来计算重复数。
也就是说,你的工作不是数字而是成对(数量,频率)(你可能会使用一些聪明的内存效率表示,例如两个数组而不是数组对等)。
你从[(x1,1),(x2,1),...]开始并像往常一样进行合并,但是当你合并两个以相同值开头的列表时,你将值放入输出列出他们的出现总和。在你的例子中:
[1:1,1:1,2:1,1:1,4:1,5:1,2:1]
Split into [1:1, 1:1, 2:1] and [1:1, 4:1, 5:1, 2:1]
Recursively process them; you get [1:2, 2:1] and [1:1, 2:1, 4:1, 5:1]
Merge them: (first / second / output)
[1:2, 2:1] / [1:1, 2:1, 4:1, 5:1] / [] - we add up 1:2 and 1:1 and get 1:3
[2:1] / [2:1, 4:1, 5:1] / [1:3] - we add up 2:1 and 2:1 and get 2:2
[] / [4:1, 5:1] / [1:3, 2:2]
[1:3, 2:2, 4:1, 5:1]
通过使用一些巧妙的技巧来进行数组的初始缩减(可以获得一个值数组:比原始数据小得多的出现对,但每个'值'的'出现'的总和'等于原始数组中'value'的出现次数)。例如,将数组拆分为连续块,其中值相差不超过256或65536,并使用小数组计算每个块内的出现次数。实际上,这个技巧也可以在以后的合并阶段应用。
答案 2 :(得分:1)
使用示例中的整数数组,最有效的方法是使用int
数组并使用您的值对其进行索引(如您所看到的那样)。
如果你不能这样做,我想不出比hashmap更好的选择。您只需要一个快速哈希算法。如果要使用所有数据,则不能比O(n)性能更好。是否只使用您拥有的部分数据?
(请注意,排序和计数比使用基于散列映射的解决方案(O(n))渐近地慢(O(n * log(n)))。)