获取数组中 n 个最小元素的索引
Posted
技术标签:
【中文标题】获取数组中 n 个最小元素的索引【英文标题】:get indexes of n smallest elements in an array 【发布时间】:2011-02-16 13:45:20 【问题描述】:我有一个 int 数组 int[] myArray = new int[100];
并且想要获取最小 10(任意 n)个元素的索引。我该怎么做?
【问题讨论】:
如果您展示了您的尝试,这将有助于社区提供更好的帮助。具体来说,如果您正在尝试某些代码并且它运行不正常,最好向我们展示似乎无法正常运行的 sn-p。 @erasmus 他在问这是否用于家庭作业。标记为作业的问题会收到不同的答案。例如 How do I sort an array with[homework]
tag 将导致对不同排序算法的解释,没有它,将得到Arrays.sort( list );
@Oscar,我不认为他是真诚的。像他这样的人也有。他们所做的是降低问题的投票值并编写一些挑衅性的 cmets。那些家伙只是没用的东西。
@erasmus:有时问题以不清楚的方式发布。我不得不读了好几遍,因为我不太明白。我添加了我的答案,看看是不是你需要的。
@erasmus:我必须同意 Oscar 的观点——这个问题在我看来是一个家庭作业式的问题。
【参考方案1】:
排序数组然后选择 10 很简单,但它会是 O(n log n),如果你不想重新排序初始数组,你也需要复制一份。
一个更好的主意是使用最大堆(或优先级队列),它会在您插入元素时自动对元素进行排序,这样最大的元素就是根节点。沿着数组走,继续放入元素,直到达到 10;然后,对于每个后续元素,只需检查它是否小于堆中最大的元素(恒定时间检查),如果是,则将其弹出并插入新元素。当你遍历整个数组时,里面剩下的 10 个东西就是你的最小元素。这会让你得到 O(n log 10) == O(n) 的结果,因为每次插入堆只花费 O(log 10)。
Java 的 Priority Queue 实现默认是最小队列,因此您需要传入一个反转排序的 Comparator。有关如何执行此操作的示例,请参阅this question。如果您想在最后获取索引,您还需要创建一个包含 (value, index) 对的自定义对象。
【讨论】:
【参考方案2】:创建一个包含数字和索引的对象,然后创建这些对象的数组,然后执行 Array.Sort(arrayset[],comparator)java docs。然后你就可以从排序后的数组中挑选出前 x 项。
编辑: 像这样的东西...... [我用这个根据'距离'进行排序
import java.util.Arrays;
import java.util.Comparator;
public class NearestObject
public NearestObject(int position, int distance)
this.Position = position;
this.Distance = distance;
public int Position = 0;
public int Distance = 0;
public static NearestObject[] SortDistance(NearestObject[] items)
Arrays.sort(items, new DistanceSort());
return items;
class DistanceSort implements Comparator<NearestObject>
public int compare(NearestObject o1, NearestObject o2)
return o1.Distance - o2.Distance;
【讨论】:
【参考方案3】:直接的解决方案是遍历数组并维护您找到的 n 个最小元素及其索引的列表。这是一个 O(N) 的解决方案,在大多数情况下都可以接受。我猜这是家庭作业,你必须有比 O(N) 更好的东西。
【讨论】:
不是 O(n*m) 吗? (n=输入大小,m=项目数) @Kurru,诚然,我的回答的细节并不完全清楚。我认为这个问题以前被标记为作业。我不认为它是 O(NM) 因为不必遍历 M 元素的列表。一旦找到第 M 个最小的元素,N 列表上的所有后续迭代只需要根据第 M 个元素检查自己。我认为最好通过使用优先级堆来促进这种行为。所以... O(Nlog(M)) ??? 所以我想我的答案只是@tzaman 答案的描述性较差的版本。 优先级循环是否在最坏的情况下插入和读取日志(M)?不知道 在读取堆时,通常会关注最小值或最大值,实现通常允许 O(1) 的读取复杂度。插入/删除复杂度为 O(logN)。这是 Java 的 PriorityQueue:download.oracle.com/javase/6/docs/api/java/util/… 该类的 javadoc 的最后一行描述了当前实现所保证的时间复杂度。【参考方案4】:按索引排序并返回前 10 个
首先创建一个结构来保存索引和值:
class IndexValue
final int i;
final int v;
然后用这个新结构创建一个数组:
IndexValue[] array = new IndexValue[myArray.length];
for( int i = 0 ; i < array.length ; i++ )
array[i] = new IndexValue( i, myArray[i] );
最后排序,取前N个元素
Arrays.sort( array ); // you'll need to implement Comparator though
for( int i = 0 ; i< 10 ;i++ )
System.out.print( array[i] );
这是完整的工作代码:
import java.util.Arrays;
import java.util.Random;
import java.util.Comparator;
import static java.lang.System.out;
class IndexValue
final int i,v;
public IndexValue( int i, int v )
this.i = i;
this.v = v;
public class SortByIndex
public static void main( String [] args )
Random random = new Random();
int [] myArray = new int[100];
IndexValue[] array = new IndexValue[myArray.length];
// Fill the array
for( int i = 0 ; i < 100; i++ )
myArray[i] = random.nextInt();
array[i] = new IndexValue( i, myArray[i] );
// Sort it
Arrays.sort( array, new Comparator<IndexValue>()
public int compare( IndexValue a, IndexValue b )
return a.v - b.v;
);
// Print it
out.println("Top:");
for( int i = 0 ; i < 10 ; i++ )
out.println( String.format("array[%d]=%d", array[i].i, array[i].v ));
【讨论】:
【参考方案5】:您可以对数组进行排序,循环前 10 个元素,然后为每个元素在数组中搜索它所在的位置...也许这不是更有效的方法,但它更容易。
【讨论】:
【参考方案6】:如果您正在寻找一个实用的答案(相对于实际的排序算法等),那么只需使用 HashMap 或 PriorityQueue。如果速度不是问题,试试这个简单的算法。它比 PriorityQueue 更容易,因为您不需要自定义对象:
HashMap<Integer, ArrayList<Integer>> indexMap = new HashMap<Integer, ArrayList<Integer>>();
填写 indexMap 以便我们可以获取数组中任何给定数字的索引
for (int index = 0; index <= array.size; index++)
if (indexMap.get(array[index]) == null) // Prime it with an ArrayList
indexMap.put(array[index], new ArrayList<Integer>());
indexMap.get(array[index]).add(index);
对于数组中最小的 n 个数,打印出它们的索引。
Arrays.sort(array);
for (int index = 0; index <= n; index++)
System.out.println(indexMap.get(array[index]).remove(0));
【讨论】:
以上是关于获取数组中 n 个最小元素的索引的主要内容,如果未能解决你的问题,请参考以下文章