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

时间:2008-10-18 16:53:10

标签: java sorting

我有一大堆原始类型(double)。 如何按降序对元素进行排序?

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

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

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;
}

这很慢 - 特别是如果数组已经很好地排序了。

什么是更好的选择?

22 个答案:

答案 0 :(得分:16)

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的内置dual-pivot quicksort。这意味着速度应该接近内置排序的速度。

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

答案 1 :(得分:15)

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

是的,我看到了“降序”部分。排序是困难的部分,您希望从Java库代码的简单性和速度中受益。一旦完成,你只需反转数组,这是一个相对便宜的O(n)操作。 Here's some code我发现只用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;
}

答案 2 :(得分:8)

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]

答案 3 :(得分:4)

double[] array = new double[1048576];

...

默认顺序为升序

扭转顺序

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

答案 4 :(得分:2)

使用Java 8中的流在这里实现一线化

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

答案 5 :(得分:2)

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

  1. 获取数组的自然顺序
  2. 在排序数组中找到最大项目
  3. 的最大值
  4. 使用带减量运算符的for循环
  5. 正如其他人之前所说:使用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
        }
    }
    

答案 6 :(得分:1)

在其他答案中,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。结果List将double []数组作为自己的元素。你想要的是List<Double>,其元素是double[]的元素。

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

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

答案 7 :(得分:1)

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];

答案 8 :(得分:1)

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

答案 9 :(得分:1)

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

您最好的选择是为您的用例实现(或借用实现)排序算法appropriate 以对数组进行排序(在您的情况下以相反的顺序)。

答案 10 :(得分:1)

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

当然你可以写自己的排序。这可能不是您正在寻找的答案,但是请注意,如果您的评论“如果数组已经排序得很好”经常发生,您可能会选择处理的排序算法这种情况很好(例如插入)而不是使用Arrays.sort()(如果元素的数量很小,则为mergesort或插入)。

答案 11 :(得分:0)

如果性能很重要,那么列表通常已经很好地排序了。

冒泡排序应该是最慢的排序方式之一,但我已经看到了最佳性能是简单的双向冒泡排序的情况。

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

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

答案 12 :(得分:0)

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

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;
}

答案 13 :(得分:0)

对于小数组,这可能有用。

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!

答案 14 :(得分:0)

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

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

答案 15 :(得分:0)

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

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

答案 16 :(得分:0)

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

它是如何工作的?它需要一个整数数组作为参数。之后,它将创建一个新数组,该数组将包含与参数中的数组相同的值。这样做的原因是保留原始数组。

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

要获得详尽的说明,请查看我的博文here

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;
}

答案 17 :(得分:0)

了解这是一个非常古老的文章,但是我偶然发现了一个类似的问题,试图对原始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);

答案 18 :(得分:0)

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

答案 19 :(得分:0)

这是一个完整的程序,可以根据内部字段对对象进行排序。

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);
    }
}

答案 20 :(得分:-1)

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()

答案 21 :(得分:-1)

在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]