我有一个浮点值数组,想要值,更重要的是想要最多四个值的位置。

我最初构建系统是为了遍历数组,并通过将当前位置的值与记录的最大值相比较来找到最常用的方法,并在最大到目前为止更新位置变量变化。这很好用,一个非常简单的O(n)算法。我后来才知道,我不仅需要保持最高价值,还要保持前三或者前四名。我扩展了相同的程序并将最大程度的复杂化为四个最大化的数组,现在代码很难看。

它仍然有效并且仍然足够快,因为只有少量的计算被添加到该过程。它仍然有效地遍历数组并检查每个值一次。

我在MATLAB中使用sort函数执行此操作,该函数返回两个数组,排序列表和随附的原始位置列表。通过查看前几个值,我确切地知道我需要什么。我正在将此功能复制到C#.NET 2.0程序中。

我知道我可以用List对象做类似的事情,并且List对象有一个内置的排序例程,但我不相信它可以告诉我原来的位置,那些真的是我追求的。

它一直运作良好,但现在我发现自己想要第五个最大值,并且看到重写最大的远程检查器,这个目前是一个丑陋的if语句只会使丑陋复杂化。它会工作得很好并且添加第五级也不会慢,但我想询问SO社区是否有更好的方法。

对整个列表进行排序需要比我当前的方法多得多的计算,但我不认为这会是一个问题,因为列表“只有”一两千个浮点数;因此,如果有一个可以回馈原始位置的排序例程,那将是理想的。

作为背景,此数组是对千字节波形文件进行傅里叶变换的结果,因此最大值的位置对应于样本数据的峰值频率。我对前四名感到满意,但看到需要真正收集前五或六,以便更准确地进行样本分类。

有帮助吗?

解决方案

我可以建议一种替代算法,你必须编码:)

使用大小为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

其他提示

您仍然可以使用列表构思 - 您在列表中放置的元素可以是存储索引和值的结构;但只对值进行排序,例如:

class IndexAndValue : IComparable<IndexAndValue>
{
    public int index;
    public double value;

    public int CompareTo(IndexAndValue other)
    {
        return value.CompareTo(other.value);
    }
}

然后您可以将它们粘贴在列表中,同时保留有关索引的信息。如果你只保留列表中最大的m项,那么你的效率应该是O(mn)。

我不知道你目前使用的是哪种算法,但我会建议一个简单的算法。 承认你有一个浮点数组 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 容量)。

另一种选择是使用快速选择。 快速选择返回列表中第k个元素的位置。获得第k个元素的位置和值后,遍历列表并获取其值小于/大于第k个元素的每个元素。

我在这里找到了快速选择的ac#实现:链接文字

优点:

  1. O(n + k)平均运行时间。
  2. 缺点:

    1. 找到的k个元素未排序。如果您对它们进行排序,则运行时间为O(n + logk)
    2. 我没有检查过这个,但我认为对于一个非常小的k,最好的选择是在数组上运行k,每次都找到下一个最小/最大的元素。
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top