我有一个浮点值数组,想要值,更重要的是想要最多四个值的位置。
我最初构建系统是为了遍历数组,并通过将当前位置的值与记录的最大值相比较来找到最常用的方法,并在最大到目前为止更新位置变量变化。这很好用,一个非常简单的O(n)算法。我后来才知道,我不仅需要保持最高价值,还要保持前三或者前四名。我扩展了相同的程序并将最大程度的复杂化为四个最大化的数组,现在代码很难看。
它仍然有效并且仍然足够快,因为只有少量的计算被添加到该过程。它仍然有效地遍历数组并检查每个值一次。
我在MATLAB中使用sort函数执行此操作,该函数返回两个数组,排序列表和随附的原始位置列表。通过查看前几个值,我确切地知道我需要什么。我正在将此功能复制到C#.NET 2.0程序中。
我知道我可以用List对象做类似的事情,并且List对象有一个内置的排序例程,但我不相信它能告诉我原来的位置,那些真的是我追求的。
它一直运作良好,但现在我发现自己想要第五个最大值,并且看到重写最大的远程检查器,这个目前是一个丑陋的if语句只会使丑陋复杂化。它会工作得很好并且添加第五级也不会慢,但我想询问SO社区是否有更好的方法。
对整个列表进行排序需要比我当前的方法多得多的计算,但我不认为这会是一个问题,因为列表“只有”一两千个浮点数;因此,如果有一个可以回馈原始位置的排序例程,那将是理想的。
作为背景,此数组是对千字节波形文件进行傅里叶变换的结果,因此最大值的位置对应于样本数据的峰值频率。我对前四名感到满意,但看到需要真正收集前五或六,以便更准确地进行样本分类。
答案 0 :(得分:9)
我可以建议一种替代算法,你必须编码:)
使用大小为K的堆,其中K表示要保存的顶部元素的数量。将其初始化为原始数组的前K个元素。对于所有N-K元素遍历数组,在需要时插入。
proc top_k (array<n>, heap<k>)
heap <- array<1..k-1>
for each (array<k..n-1>)
if array[i] > heap.min
heap.erase(heap.min)
heap.insert(array[i])
end if
end for
答案 1 :(得分:2)
您仍然可以使用列表构思 - 您在列表中放置的元素可以是存储索引和值的结构;但只对值进行排序,例如:
class IndexAndValue : IComparable<IndexAndValue>
{
public int index;
public double value;
public int CompareTo(IndexAndValue other)
{
return value.CompareTo(other.value);
}
}
然后您可以将它们粘贴在列表中,同时保留有关索引的信息。如果你只保留列表中最大的m项,那么你的效率应该是O(mn)。
答案 2 :(得分:2)
我不知道你目前使用的是哪种算法,但我会建议一个简单的算法。
承认您有一系列浮点数f
且最多为capacity
数字,您可以执行以下操作:
int capacity = 4; // number of floats you want to retrieve
float [] f; // your float list
float [] max_so_far = new float[capacity]; // max so far
// say that the first 'capacity' elements are the biggest, for now
for (int i = 0; i < capacity; i++)
max_so_far[i] = i;
// for each number not processed
for (int i = capacity; i < f.length; i++)
{
// find out the smallest 'max so far' number
int m = 0;
for (int j = 0; j < capacity; j++)
if (f[max_so_far[j]] < f[max_so_far[m]])
m = j;
// if our current number is bigger than the smallest stored, replace it
if (f[i] > f[max_so_far[m]])
max_so_far[m] = i;
}
在算法结束时,您将拥有存储的最大元素的索引
在max_so_far
。
请注意,如果capacity
值增加,它将略微变慢
替代方案,即在跟踪初始位置的同时对列表进行排序。
请记住,排序需要进行O(n log n)比较,而此算法需要O(n 容量)。
答案 3 :(得分:1)
另一种选择是使用快速选择。 快速选择返回列表中第k个元素的位置。获得第k个元素的位置和值后,遍历列表并获取其值小于/大于第k个元素的每个元素。
我在这里找到了快速选择的c#实现:link text
优点:
缺点: