Java未排序的Doubles ArrayList,如何获取最高值的索引?

时间:2011-04-07 20:19:58

标签: java arraylist

伙计我有一个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个值(双精度)的索引号?

任何帮助赞赏的人,

6 个答案:

答案 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等语言,您只需使用zipWithIndexsortWithtake (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)。