我有一个尺寸为N×N的2D阵列(实际上是图像)。我需要找到阵列中M个最大值的索引(M 我对数组进行完全传递很好(即O(N ^ 2)很好)。任何人都有一个很好的算法,尽可能有效地做到这一点?
答案 0 :(得分:7)
Selection正在排序严峻的姐姐(连续十次重复)。选择算法比排序算法知之甚少,但仍然有用。
这里你不能比O(N ^ 2)(在N中)做得更好,因为没有任何东西表明你不能访问数组的每个元素。
一个好方法是保持由M个最大元素组成的priority queue。这使得O(N x N x log M)。
您遍历数组,随时将对(元素,索引)排入队列。队列保持其元素按第一个组件排序。
一旦队列中有M个元素,而不是现在将你排队:
如果M更大,则最好对数组进行排序。
注意: @Andy Finkenstadt提出了一个很好的观点(在你的问题的评论中):你肯定应该在“数据位置的方向”遍历你的数组:确保你连续读取内存
此外,这是可以简单地并行化的,唯一不可并行化的部分是在加入子进程时合并队列。
答案 1 :(得分:0)
您可以将数组复制到单个维度的元组数组(值,原始X,原始Y),并在(O(n)时间)内构建基本堆,前提是您将堆实现为数组。
然后你可以在O(M lg n)时间内检索M个最大元组,并从元组中引用它们的原始x和y。
答案 2 :(得分:0)
如果要打算输入数组的副本以进行排序,那么这比直接走完整个事物来挑选数字更糟糕。
所以问题是你的M有多大?如果它很小,您可以将结果(即具有2D索引和值的结构)存储在简单数组或向量中。这样可以最大限度地减少堆操作,但是当你发现一个比你的向量更大的值时,你将不得不改变它。
如果您希望M变得非常大,那么您可能需要更好的数据结构,如二叉树(std :: set)或使用sorted std :: deque。 std :: set将减少元素必须在内存中移位的次数,而如果你使用std :: deque,它会做一些移动,但它会减少你必须显着去堆的次数,可能会给你更好的表现。
答案 3 :(得分:0)
你的问题没有以任何有趣的方式使用2维,更容易在二维数组中包含等效问题。
有两种主要方法可以解决这个问题:
Mantain一组M个最大元素,并遍历数组。 (使用堆允许您有效地执行此操作)。
这很简单,在您的情况下可能更好(M<< N)
使用选择,(以下算法是quicksort的改编版):
这对于大M的情况很有用。如果你想避免最坏的情况(同样的快速排序),那么看看更高级的算法,(比如中位选择的中位数)
答案 4 :(得分:0)
您从阵列中搜索最大值的次数是多少? 如果您只搜索一次,那么只需扫描它,保留M个最大值。
如果您多次执行此操作,只需将值插入到排序列表中(最好将其作为平衡树实现)。