伙计我有一个ArrayList,其中包含大约3000个双值。
我基本上需要ArrayList中前100个双精度的有序索引。 我不关心前100名的实际值,只关注他们的索引,从最大到最小。
例如,如果ArrayList中的最大值(从最大值到最小值)是index50,index27和index96,那么我只能以50,27,96的形式与此完全相符。
ArrayList的代码:
ArrayList<Double> ids = new ArrayList<Double>();
结果集或索引列表可以包含在任何数据结构中,该结构维护50,27,96的顺序,例如ArrayList或任何其他集合类型。
摘要:
如何返回ArrayList中最高100个值(双精度)的索引号?
任何帮助赞赏的人,
答案 0 :(得分:2)
您可以将所有值(作为键)索引(作为值)对添加到TreeMap(或其他SortedMap
s)
SortedMap.values
以排序顺序返回值(即indeces)。
编辑:如果列表中有重复项,则无法使用此功能,因为第二次执行将覆盖以前存储的值(索引)。所以以下似乎更好:
创建索引和值对,将它们添加到SortedSet(如下面建议的StKiller),使用按值排序然后按索引排序的比较器(与一致的等于作为API -doc把它)。然后只需要前100对,或者更确切地说是那些存储的那些。
编辑2:实际上,您并不真正需要这些对,您可以使用Comparator for indeces来查找值......
答案 1 :(得分:2)
我猜插入排序在O(n ^ 2)时间运行。使用在O(nlog(n))时间运行的堆排序。使用100个节点的最小堆。迭代列表时,将值与根进行比较。如果它更大,请替换root并运行heapify算法。
完成所有元素后,您的堆将包含前100个元素。
使用适当的堆数据结构将使您可以保留索引以及值。
一个例子可能是
class MinHeapNode
{
public int value;
public int index;
public MinHeapNode left;
public MinHeapNode right;
}
答案 2 :(得分:2)
我认为如果你只需要前100个值,为什么不使用在100次迭代后切断的反向选择排序?选择排序保证在每次传递时将一个值放入正确的位置,因此在100次运行列表后,最高值应该是您想要的值。我确信存在一个更优雅的解决方案,但这应该很容易实现。
答案 3 :(得分:2)
import java.util.*;
在完成关于排序的O(事物)之后,我想我应该表明实际上插入排序在这种情况下是最好的。下面的代码显示了此页面中的各种建议和我自己的想法。相对表现是:
插入排序:61 480ns
对象排序:1 147 538ns
排序集:671 007ns
限量套装:435 130ns
public class DoubleIndexSort {
static class DI implements Comparable<DI> {
final int index;
final double val;
DI(double v, int i) {
val = v;
index = i;
}
public int compareTo(DI other) {
if (val < other.val) {
return 1;
} else if (val == other.val) {
return 0;
}
return -1;
}
}
public static void checkResult(double[] test, int[] indexes) {
for(int i = 0;i < indexes.length;i++) {
int ii = indexes[i];
double iv = test[ii];
// System.out.println("Checking " + i + " -> " + ii + " = " + iv);
for(int j = 0;j < test.length;j++) {
// System.out.println(j + " -> " + test[j]);
if (j != ii && test[j] > iv) throw new RuntimeException();
}
test[ii] = -1;
}
}
public static int[] getHighestIndexes(double[] data, int topN) {
if (data.length <= topN) {
return sequence(topN);
}
int[] bestIndex = new int[topN];
double[] bestVals = new double[topN];
bestIndex[0] = 0;
bestVals[0] = data[0];
for(int i = 1;i < topN;i++) {
int j = i;
while( (j > 0) && (bestVals[j - 1] < data[i]) ) {
bestIndex[j] = bestIndex[j - 1];
bestVals[j] = bestVals[j - 1];
j--;
}
bestVals[j] = data[i];
bestIndex[j] = i;
}
for(int i = topN;i < data.length;i++) {
if (bestVals[topN - 1] < data[i]) {
int j = topN - 1;
while( (j > 0) && (bestVals[j - 1] < data[i]) ) {
bestIndex[j] = bestIndex[j - 1];
bestVals[j] = bestVals[j - 1];
j--;
}
bestVals[j] = data[i];
bestIndex[j] = i;
}
}
return bestIndex;
}
public static int[] getHighestIndexes2(double[] data, int topN) {
if (data.length <= topN) {
return sequence(topN);
}
DI[] di = new DI[data.length];
for(int i = 0;i < data.length;i++) {
di[i] = new DI(data[i], i);
}
Arrays.sort(di);
int[] res = new int[topN];
for(int i = 0;i < topN;i++) {
res[i] = di[i].index;
}
return res;
}
public static int[] getHighestIndexes3(double[] data, int topN) {
if (data.length <= topN) {
return sequence(topN);
}
SortedSet<DI> set = new TreeSet<DI>();
for(int i=0;i<data.length;i++) {
set.add(new DI(data[i],i));
}
Iterator<DI> iter = set.iterator();
int[] res = new int[topN];
for(int i = 0;i < topN;i++) {
res[i] = iter.next().index;
}
return res;
}
public static int[] getHighestIndexes4(double[] data, int topN) {
if (data.length <= topN) {
return sequence(topN);
}
SortedSet<DI> set = new TreeSet<DI>();
for(int i=0;i<data.length;i++) {
set.add(new DI(data[i],i));
if( set.size() > topN ) {
set.remove(set.last());
}
}
Iterator<DI> iter = set.iterator();
int[] res = new int[topN];
for(int i = 0;i < topN;i++) {
res[i] = iter.next().index;
}
return res;
}
/**
* @param args
*/
public static void main(String[] args) {
long elap1 = 0;
long elap2 = 0;
long elap3 = 0;
long elap4 = 0;
for(int i = 1;i <= 1000;i++) {
double[] data = testData();
long now = System.nanoTime();
int[] inds = getHighestIndexes(data, 100);
elap1 += System.nanoTime() - now;
checkResult(data, inds);
System.out.println("\nInsert sort: "+(elap1 / i));
now = System.nanoTime();
inds = getHighestIndexes2(data, 100);
elap2 += System.nanoTime() - now;
checkResult(data, inds);
System.out.println("Object sort: "+(elap2 / i));
now = System.nanoTime();
inds = getHighestIndexes3(data, 100);
elap3 += System.nanoTime() - now;
checkResult(data, inds);
System.out.println("Sorted set: "+(elap3 / i));
now = System.nanoTime();
inds = getHighestIndexes4(data, 100);
elap4 += System.nanoTime() - now;
checkResult(data, inds);
System.out.println("Limited set: "+(elap4 / i));
}
}
private static int[] sequence(int n) {
int[] indexes = new int[n];
for(int i = 0;i < n;i++) {
indexes[i] = i;
}
return indexes;
}
public static double[] testData() {
double[] test = new double[3000];
for(int i = 0;i < test.length;i++) {
test[i] = Math.random();
}
return test;
}
}
答案 4 :(得分:1)
使用插入排序。这可以在O(n ^ 2)中完成。维护一个List,它包含您拥有的ArrayList的前100个值。遍历您拥有的ArrayList并使用Insertion排序将顶部元素放在新的ArrayList中。
答案 5 :(得分:1)
使用scala等语言,您只需使用zipWithIndex
,sortWith
,take (n)
和map
:
val ids = List (2.0, 2.5, 1.5, 0.5, 7.5, 7.0, 1.0, 8.0, 4.0, 1.0);
ids.zipWithIndex.sortWith ((x, y) => (x._1 > y._1)).take (3).map (vi => vi._2)
res65: List[Int] = List(7, 4, 5)
但是,在Java中,如果调用scala(与java 100%兼容),则必须执行更多的样板代码。
然而,functional java可以实现几乎同样简单的解决方案(参见API,List)。