【问题标题】:Getting the largest k elements of a double array获取双精度数组的最大 k 个元素
【发布时间】:2014-09-12 06:27:08
【问题描述】:

我面临的问题是这个:

我有一个doubles 数组,我想从中保留顶部k 更大的值。

  1. 我见过一些涉及Arrays.sort 的实现。例如在 this example 中存在相关问题,建议使用这种方法。
  2. 因为我只对第一个k 元素感兴趣,所以我还尝试了MinMaxPriorityQueue。我创建了一个MinMaxPriorityQueue 和一个maximumSize

当然还有自动装箱。

Builder<Comparable> builder = MinMaxPriorityQueue.maximumSize(maximumSize);
MinMaxPriorityQueue<Double> top2 = builder.create();

问题是顺序是升序的,它与我想要的相反。所以我不能这样用。

为了说明问题的真实参数,我的数组大约是 50 元素长,我对最上面的 k = 5 元素感兴趣。

那么有没有办法使用第二种方法绕过这个问题?即使我真的不需要对所有元素进行排序,我是否应该保留第一个?你知道速度性能是否有任何显着差异(我将不得不在很多情况下使用它,所以这就是需要速度的地方)?我可以使用其他解决方案吗?

至于性能,我知道理论上我可以自己检查它,但我有点没时间了,如果有人有任何解决方案,我很高兴听到它(或无论如何阅读它)。

【问题讨论】:

  • Arrays.sort(new double[]{...}) 不涉及自动装箱。
  • 是的,但它不适用于 double[] 的相反顺序
  • 为什么需要逆序?只需对其进行排序,然后取最后一个 k 元素。
  • 是的,你说得对。
  • 如果您只有 50 个元素,那么您太担心性能了,除非您打算在非常小的设备(旧的 android 手机?)上运行您的程序。你打算扩展它来处理非常大的数组吗?

标签: java arrays sorting


【解决方案1】:

如果您只有 50 个元素,如我的评论中所述,只需对其进行排序并取最后一个 k 元素。它只有 2 行:

public static double[] largests(double[] arr, int k) {
    Arrays.sort(arr);
    return Arrays.copyOfRange(arr, arr.length - k, arr.length);
}

这会修改(排序)原始数组。如果你希望你的原始数组不被修改,你只需要 +1 行:

public static double[] largests2(double[] arr, int k) {
    arr = Arrays.copyOf(arr, arr.length);
    Arrays.sort(arr);
    return Arrays.copyOfRange(arr, arr.length - k, arr.length);
}

【讨论】:

  • 这将改变arr 中元素的顺序,请注意,当您尝试使用它时。
  • 是的,你是对的。添加了不修改原始数组的修改版本。
  • 这是我的第一个算法^^ 请注意,根据 javadoc 的运行时间是 O(N*log(N))。我用O(N*k*log(k)) 写了一个,对于小k 和大N 来说更快,尤其是在k 不变的情况下是线性的。
  • 是的,我刚刚使用Arrays 将代码行数减半。
【解决方案2】:

您可以在排序数组上使用System.arraycopy

double[] getMaxElements(double[] input, int k) {
    double[] temp = Arrays.copyOf(input, input.length);
    Arrays.sort(temp); // Sort a copy to keep input as it is since Arrays.sort works in-place.
    return Arrays.copyOfRange(temp, temp.length - k, temp.length); // Fetch largest elements
}

对于 50 个元素,对数组进行排序比使用泛型和可比较对象要快得多。
我会写一个额外的“快速”算法......

double[] getMaxElements2(double[] input, int k) {
    double[] res = new double[k];
    for (int i = 0; i < k; i++) res[i] = Double.NEGATIVE_INFINITY; // Make them as small as possible.
    for (int j = 0; j < input.length; j++) // Look at every element
        if (res[0] < input[j]) { // Keep the current element
            res[0] = input[j];
            Arrays.sort(res); // Keep the lowest kept element at res[0]
        }
    return res;
}

这是O(N*k*log(k)),而第一个是O(N*log(N))

【讨论】:

  • 请注意Arrays.copyOf() 也需要长度(否则编译错误)。
  • @icza 谢谢,已修复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-07
  • 1970-01-01
  • 2013-02-11
  • 2020-12-11
  • 1970-01-01
相关资源
最近更新 更多