代码之家  ›  专栏  ›  技术社区  ›  Benedikt Waldvogel assylias

按降序对基元类型的数组排序

  •  44
  • Benedikt Waldvogel assylias  · 技术社区  · 17 年前

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

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

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

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

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

    什么是更好的选择?

    20 回复  |  直到 7 年前
        1
  •  16
  •   Brandon    11 年前

    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原始库。

        2
  •  14
  •   GorvGoyl    9 年前

    我认为最好不要重新发明轮子并使用array.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;
    }
    
        3
  •  8
  •   Sean Patrick Floyd    15 年前

    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〕

        4
  •  4
  •   vitaut    12 年前
    double[] array = new double[1048576];
    

    …

    默认情况下,顺序为升序

    颠倒顺序

    Arrays.sort(array,Collections.reverseOrder());
    
        5
  •  2
  •   madfree    10 年前

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

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

    正如前面其他人所说:使用tolist是额外的工作,array.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
  •   Jason Cohen    17 年前

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

    当然你可以自己写。这可能不是你想要的答案, 但是 请注意,如果您对“如果数组已经排序得很好”的评论频繁出现,那么您最好选择一种处理该情况的排序算法(例如插入),而不是使用 Arrays.sort() (这是mergesort,如果元素数量小,则插入)。

        7
  •  1
  •   Eli Courtwright    17 年前

    关于 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个元素的列表。结果列表将double[]数组作为自己的元素。你想要的是 List<Double> 其元素是 double[] .

    不幸的是,涉及比较器的任何解决方案都不能用于原始数组。 Arrays.sort 仅当传递 Object[] . 基于上述原因, 阿拉斯 不会让您用数组的元素列出一个列表。

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

        8
  •  1
  •   Krystian Cybulski    17 年前

    不能使用比较器对基元数组进行排序。

    您最好的选择是实现(或借用实现)排序算法,即 appropriate 让您的用例对数组进行排序(在您的用例中按相反的顺序)。

        9
  •  1
  •   greybeard    11 年前

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

        10
  •  1
  •   Shravan Kumar    9 年前
    Before sorting the given array multiply each element by -1 
    

    然后使用数组。排序(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];
    
        11
  •  0
  •   Leo    17 年前

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

    从我的实验中 D programming language (类似于类固醇的C语言),我发现合并排序算法可以说是最快的通用排序算法(D语言本身就是用它来实现排序函数的)。

        12
  •  0
  •   myplacedk    17 年前

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

    气泡排序应该是最慢的排序方式之一,但我已经看到过这样的情况:最好的性能是简单的双向气泡排序。

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

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

        13
  •  0
  •   OneCricketeer Gabriele Mariotti    9 年前

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

    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
  •   OneCricketeer Gabriele Mariotti    9 年前

    你的算法是正确的。但是我们可以做如下优化: 在反转时,您可以尝试保留另一个变量来减少自数组计算以来的反向计数器。长度(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;
    }
    
        15
  •  0
  •   tanghao    9 年前

    如果使用Java8,只需将数组转换为流,排序并转换回。 所有的任务都可以在一行中完成,所以我觉得这样做还不错。

    double[] nums = Arrays.stream(nums).boxed().
            .sorted((i1, i2) -> Double.compare(i2, i1))
            .mapToDouble(Double::doubleValue)
            .toArray();
    
        16
  •  0
  •   Catalin Pit    8 年前

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

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

    一旦新数组包含复制的数据,我们就通过交换值对其进行排序,直到条件 如果(newarr[i]<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
  •   MJA    7 年前

    了解这是一篇非常古老的文章,但我在尝试对原始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
  •   Shubham Gaur    7 年前
    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
  •  -1
  •   Green Beret    12 年前
    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()。

        20
  •  -1
  •   kimbaudi    8 年前

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