[英]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 库。
这是一个单行代码,使用 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]
我认为最简单的解决方案仍然是:
正如之前其他人所说:使用 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.