繁体   English   中英

按降序对基本类型数组进行排序

[英]Sort arrays of primitive types in descending order

我有一个阵的基本类型(双)的。 如何按降序对元素进行排序

不幸的是,Java API 不支持使用 Comparator 对原始类型进行排序。

可能想到的第一种方法是将其转换为对象列表(装箱):

double[] array = new double[1048576];    
Arrays.stream(array).boxed().sorted(Collections.reverseOrder())…

但是,将数组中的每个原语装箱太慢,并且会导致很大的 GC 压力

另一种方法是排序然后反转:

double[] array = new double[1048576];
...
Arrays.sort(array);
// reverse the array
for (int i = 0; i < array.length / 2; i++) {
     // swap the elements
     double temp = array[i];
     array[i] = array[array.length - (i + 1)];
     array[array.length - (i + 1)] = temp;
}

这种方法也很慢- 特别是如果数组已经排序得很好。

什么是更好的选择?

Java Primitive包括基于自定义比较器对原始数组进行排序的功能。 使用它和 Java 8,您的示例可以编写为:

double[] array = new double[1048576];
...
Primitive.sort(array, (d1, d2) -> Double.compare(d2, d1), false);

如果您使用的是 Maven,则可以将其包含在:

<dependency>
    <groupId>net.mintern</groupId>
    <artifactId>primitive</artifactId>
    <version>1.2.1</version>
</dependency>

当您将false作为第三个参数传递给sort ,它使用不稳定的排序,这是 Java 内置双枢轴快速排序的简单编辑。 这意味着速度应该接近内置排序的速度。

完全披露:我编写了 Java Primitive 库。

我认为最好不要重新发明轮子并使用 Arrays.sort()。

是的,我看到了“下降”部分。 排序是困难的部分,您希望从 Java 库代码的简单性和速度中受益。 完成后,您只需反转数组,这是一个相对便宜的 O(n) 操作。 这是我发现的一些代码,只需 4 行即可完成此操作:

for (int left=0, right=b.length-1; left<right; left++, right--) {
    // exchange the first and last
    int temp = b[left]; b[left]  = b[right]; b[right] = temp;
}

这是一个单行代码,使用 Java 8 中的流

int arr = new int[]{1,2,3,4,5};
Arrays.stream(arr).boxed().sorted(Collections.reverseOrder()).mapToInt(Integer::intValue).toArray();

Guava具有将原始数组转换为包装类型列表的方法。 好的部分是这些列表是实时视图,因此对它们的操作也适用于底层数组(类似于Arrays.asList() ,但适用于原语)。

无论如何,这些列表中的每一个都可以传递给Collections.reverse()

int[] intArr = { 1, 2, 3, 4, 5 };
float[] floatArr = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
double[] doubleArr = { 1.0d, 2.0d, 3.0d, 4.0d, 5.0d };
byte[] byteArr = { 1, 2, 3, 4, 5 };
short[] shortArr = { 1, 2, 3, 4, 5 };
Collections.reverse(Ints.asList(intArr));
Collections.reverse(Floats.asList(floatArr));
Collections.reverse(Doubles.asList(doubleArr));
Collections.reverse(Bytes.asList(byteArr));
Collections.reverse(Shorts.asList(shortArr));
System.out.println(Arrays.toString(intArr));
System.out.println(Arrays.toString(floatArr));
System.out.println(Arrays.toString(doubleArr));
System.out.println(Arrays.toString(byteArr));
System.out.println(Arrays.toString(shortArr));

输出:

[5, 4, 3, 2, 1]
[5.0, 4.0, 3.0, 2.0, 1.0]
[5.0, 4.0, 3.0, 2.0, 1.0]
[5, 4, 3, 2, 1]
[5, 4, 3, 2, 1]

我认为最简单的解决方案仍然是:

  1. 获取数组的自然顺序
  2. 在该排序数组中找到最大值,然后是最后一项
  3. 使用带递减运算符的 for 循环

正如之前其他人所说:使用 toList 是额外的工作,Arrays.sort(array,Collections.reverseOrder()) 不适用于原语,并且当您需要的所有内容已经内置时,使用额外的框架似乎太复杂了,因此可能更快好...

示例代码:

import java.util.Arrays;

public class SimpleDescending {

    public static void main(String[] args) {

        // unsorted array
        int[] integerList = {55, 44, 33, 88, 99};

        // Getting the natural (ascending) order of the array
        Arrays.sort(integerList);

        // Getting the last item of the now sorted array (which represents the maximum, in other words: highest number)
        int max = integerList.length-1;

        // reversing the order with a simple for-loop
        System.out.println("Array in descending order:");
        for(int i=max; i>=0; i--) {
            System.out.println(integerList[i]);
        }

        // You could make the code even shorter skipping the variable max and use
        // "int i=integerList.length-1" instead of int "i=max" in the parentheses of the for-loop
    }
}

您的实现(问题中的实现)比例如使用toList()包装和使用基于比较器的方法更快。 自动装箱和通过比较器方法或包装的 Collections 对象运行比仅仅反转要慢得多。

当然,您可以编写自己的排序。 这可能不是您正在寻找的答案,请注意,如果您关于“如果数组已经排序得很好”的评论经常发生,那么您最好选择一种可以很好地处理这种情况的排序算法(例如插入)而不是使用Arrays.sort() (这是归并排序,如果元素数量很少,则插入)。

在其他答案中有一些关于Arrays.asList混淆。 如果你说

double[] arr = new double[]{6.0, 5.0, 11.0, 7.0};
List xs = Arrays.asList(arr);
System.out.println(xs.size());  // prints 1

那么您将拥有一个包含 1 个元素的列表。 结果 List 将 double[] 数组作为它自己的元素。 你想要的是有一个List<Double>它的元素是double[]的元素。

不幸的是,没有涉及 Comparator 的解决方案适用于原始数组。 Arrays.sort仅在传递Object[]时接受 Comparator 。 由于上述原因, Arrays.asList不会让您从数组元素中创建一个列表。

因此,尽管我之前的回答是下面的评论所引用的,但没有比在排序后手动反转数组更好的方法了。 任何其他方法(例如将元素复制到Double[]并反向排序并将它们复制回来)将代码更多且速度更慢。

对于数字类型,在排序之前和之后否定元素似乎是一种选择。 排序后相对于单个反向的速度取决于缓存,如果反向不是更快,则任何差异都可能会在噪音中消失。

您不能使用 Comparator 对原始数组进行排序。

最好的办法是实现(或借用实现) 适合您的用例的排序算法来对数组进行排序(在您的情况下以相反的顺序)。

Before sorting the given array multiply each element by -1 

然后使用 Arrays.sort(arr) 然后再次将每个元素乘以 -1

for(int i=0;i<arr.length;i++)
    arr[i]=-arr[i];
Arrays.sort(arr);
for(int i=0;i<arr.length;i++)
    arr[i]=-arr[i];

我不知道 Java 核心 API 中的任何原始排序工具。

从我对D 编程语言(一种类固醇上的 C)的实验中,我发现合并排序算法可以说是最快的通用排序算法(它是 D 语言本身用来实现其排序功能的) .

你的算法是正确的。 但是我们可以做如下优化:在反转时,您可以尝试保留另一个变量以减少反向计数器,因为 array.length-(i+1) 的计算可能需要时间! 并且还将临时声明移到外面,以便每次都不需要分配

double temp;

for(int i=0,j=array.length-1; i < (array.length/2); i++, j--) {

     // swap the elements
     temp = array[i];
     array[i] = array[j];
     array[j] = temp;
}

对于小型阵列,这可能有效。

int getOrder (double num, double[] array){
    double[] b = new double[array.length];
    for (int i = 0; i < array.length; i++){
        b[i] = array[i];
    }
    Arrays.sort(b);
    for (int i = 0; i < b.length; i++){
        if ( num < b[i]) return i;
    }
    return b.length;
}

我很惊讶数组 b 的初始加载是必要的

double[] b = array; // makes b point to array. so beware!

如果使用java8,只需将数组转换为流,排序并转换回来。 所有的任务都可以在一条线上完成,所以我觉得这种方式还不错。

double[] nums = Arrays.stream(nums).boxed().
        .sorted((i1, i2) -> Double.compare(i2, i1))
        .mapToDouble(Double::doubleValue)
        .toArray();

如果性能很重要,并且列表通常已经排序得很好。

冒泡排序应该是最慢的排序方式之一,但我见过最好的性能是简单的双向冒泡排序。

因此,这可能是您可以从自己编码中受益的少数情况之一。 但是你真的需要做对(确保至少有其他人确认你的代码,证明它有效等)

正如其他人指出的那样,从排序数组开始可能会更好,并在更改内容时保持排序。 那可能会表现得更好。

以下是我的解决方案,您可以根据自己的需要进行调整。

它是如何工作的? 它接受一个整数数组作为参数。 之后,它将创建一个新数组,该数组将包含与参数数组相同的值。 这样做的原因是保持原始数组完好无损。

一旦新数组包含复制的数据,我们就通过交换值对其进行排序,直到条件if(newArr[i] < newArr[i+1])评估为 false。 这意味着数组按降序排序。

有关详细解释,请在此处查看我的博客文章。

public static int[] sortDescending(int[] array)
{
    int[] newArr = new int[array.length];

    for(int i = 0; i < array.length; i++)
    {
        newArr[i] = array[i];
    }

    boolean flag = true;
    int tempValue;

    while(flag) 
    {
        flag = false;

        for(int i = 0; i < newArr.length - 1; i++) 
        {
            if(newArr[i] < newArr[i+1])
            {
                tempValue = newArr[i];
                newArr[i] = newArr[i+1];
                newArr[i+1] = tempValue;
                flag = true;
            }
        }
    }

    return newArr;
}

在 Java 8 中,更好、更简洁的方法可能是:

double[] arr = {13.6, 7.2, 6.02, 45.8, 21.09, 9.12, 2.53, 100.4};

Double[] boxedarr = Arrays.stream( arr ).boxed().toArray( Double[]::new );
Arrays.sort(boxedarr, Collections.reverseOrder());
System.out.println(Arrays.toString(boxedarr));

这将给出反向数组并且更像样。

输入:[13.6, 7.2, 6.02, 45.8, 21.09, 9.12, 2.53, 100.4]

输出:[100.4, 45.8, 21.09, 13.6, 9.12, 7.2, 6.02, 2.53]

了解这是一篇非常古老的帖子,但我在尝试对原始 int 数组进行排序时偶然发现了类似的问题,因此发布了我的解决方案。 欢迎提出建议/意见 -

int[] arr = {3,2,1,3};
List<Integer> list = new ArrayList<>();
Arrays.stream(arr).forEach(i -> list.add(i));
list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
double s =-1;
   double[] n = {111.5, 111.2, 110.5, 101.3, 101.9, 102.1, 115.2, 112.1};
   for(int i = n.length-1;i>=0;--i){
      int k = i-1;
      while(k >= 0){
          if(n[i]>n[k]){
              s = n[k];
              n[k] = n[i];
              n[i] = s;
          }
          k --;
      }
   }
   System.out.println(Arrays.toString(n));
 it gives time complexity O(n^2) but i hope its work

这是一个基于内部字段对对象进行排序的完整程序。

package Algorithms.BranchAndBound;

import java.util.Arrays;
import java.util.Comparator;

public class KnapSack01 {
    private class ItemVals {
        double weight;
        double cost;
        double ratio;

        public ItemVals(double weight, double cost) {
            this.weight = weight;
            this.cost = cost;
            this.ratio = weight/cost;
        }
    }

    public ItemVals[] createSortedItemVals(double[] weight, double[] cost) {
        ItemVals[] itemVals = new ItemVals[weight.length];
        for(int i = 0; i < weight.length; i++) {
            ItemVals itemval = new ItemVals(weight[i], cost[i]);
            itemVals[i] = itemval;
        }
        Arrays.sort(itemVals, new Comparator<ItemVals>() {
            @Override
            public int compare(ItemVals o1, ItemVals o2) {
                return Double.compare(o2.ratio, o1.ratio);
            }
        });
        return itemVals;
    }

    public void printItemVals(ItemVals[] itemVals) {
        for (int i = 0; i < itemVals.length; i++) {
            System.out.println(itemVals[i].ratio);
        }
    }

    public static void main(String[] args) {
        KnapSack01 knapSack01 = new KnapSack01();
        double[] weight = {2, 3.14, 1.98, 5, 3};
        double[] cost = {40, 50, 100, 95, 30};
        ItemVals[] itemVals = knapSack01.createSortedItemVals(weight, cost);
        knapSack01.printItemVals(itemVals);
    }
}
Double[] d = {5.5, 1.3, 8.8};
Arrays.sort(d, Collections.reverseOrder());
System.out.println(Arrays.toString(d));

Collections.reverseOrder() 不适用于原语,但 Double、Integer 等适用于 Collections.reverseOrder()

double[] array = new double[1048576];

...

默认顺序是升序

颠倒顺序

Arrays.sort(array,Collections.reverseOrder());

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM