Arrays.sort()用的是什么排序算法?怎么优化?

Arrays.sort()用的是快速排序算法。相信大家对于这个都是了解的。
算法的思想:
选择基准将数组一分为二,基准前面的比基准小,基准后面的比基准大,之后分别对这两部分继续之前的操作,已达到整个数组有序的目的。
算法内容描述:
先选择一个基准,指向数组开始的指针start和指向数组结束的指针end;
当start小于end的时候,如果基准的值小于end指向数组的值时,end往前移动;
当基准的值不在小于end指向数组的值的时候,交换两个指针指向的数组的值;
然后当基准的值大于start指向数组的值的时候,start往后移动;
当基准的值不大于start指向数组的值的时候,交换两个指针指向的数组的值;
返回基准的位置并进行递归操作完成排序。

代码如下:

public class Test2 {

    public static void swap(int[] arr, int j, int i){

        int temp = arr[j];
        arr[j] = arr[i];
        arr[i] = temp;
    }

    public static int partition(int arr[], int start, int end){
        assert(null != arr);
        int temp = arr[start];

        while(start < end){
            while(temp < arr[end] && start < end){
                end--;
            }
            swap(arr, start, end);
            while(temp > arr[start] && start < end){
                start++;
            }
            swap(arr, start, end);
        }
        System.out.println(Arrays.toString(arr) + "   " +  start);
        return start;
    }

    public static void partitionSort(int arr[], int start, int end){
        assert(null != arr);

        if(start < end){
            int midd = partition(arr, start, end);
            partitionSort(arr, start, midd - 1);
            partitionSort(arr, midd + 1, end);
        }
    }

    public static void main(String[] args) {
        int arr[] = {9,1,5,8,3,7,4,6,2};  
        Test2.partitionSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }
}

执行结果:
[2, 1, 5, 8, 3, 7, 4, 6, 9] 8
[1, 2, 5, 8, 3, 7, 4, 6, 9] 1
[1, 2, 4, 3, 5, 7, 8, 6, 9] 4
[1, 2, 3, 4, 5, 7, 8, 6, 9] 3
[1, 2, 3, 4, 5, 6, 7, 8, 9] 6
[1, 2, 3, 4, 5, 6, 7, 8, 9]

快速排序的优化:
①优化基准的选择
上面的程序选择的基准是数组起始位置,但是跟明显,我们并没有达到想要的理想结果将数组划分为两部分,进行递归操作;
所以就有了三数取中法来选取基准,即取三个关键字先进行排序,将中间数作为基准,一般去开始,结束,和中间;
当然也可以随机选取;其实还有一种九数取中法,这里就不详细介绍了,有兴趣的可以自己了解一下。
下面是三数取中法的代码:

public void medianOfThree(int[] arr, int start, int end){

        int m = start + (end - start) / 2;
        if(arr[start] > arr[end]){
            swap(arr, start, end);
        }
        if(arr[m] > arr[end]){
            swap(arr, end, m);
        }
        if(arr[m] > arr[start]){
            swap(arr, m, start);
        }
    }

②优化不必要的交换
首先我们通过上面的代码很容易发现在交换的过程中,有许多部分是没必要交换的,于是我们通过赋值替代交换来省去没必要的交换;

代码如下:

public int partition3(int arr[], int start, int end){
        assert(null != arr);

        medianOfThree(arr, start, end);
        int temp = arr[start];

        while(start < end){
            while(temp < arr[end] && start < end){
                end--;
            }
            arr[start] = arr[end];
            while(temp > arr[start] && start < end){
                start++;
            }
            arr[end] = arr[start];
        }
        arr[start] = temp;
        System.out.println(Arrays.toString(arr) + "   " +  start);
        return start;
    }

③优化小数组时的排序方案
一般对于小数组排序,我们需要选择插入排序,因为插入排序是简单排序性能最高的。所以我们做如下修改:

public void partitionSort4(int arr[], int start, int end){
        assert(null != arr);

        if((end - start) > INSERT_SORT){
            int midd = partition3(arr, start, end);
            partitionSort3(arr, start, midd - 1);
            partitionSort3(arr, midd + 1, end);
        }else{
            insertSort(arr);
        }
    }

其中,INSERT_SORT选择的大小众说纷纭,自我觉得在海量数据面前,选择20跟选择7没有太大的差异吧。(这话如果有误,望大家批评指正)
④优化递归操作
我们都知道递归的额外花销还是很大的,减少递归可以大大提高性能,故此做如下修改:

 public void partitionSort5(int arr[], int start, int end){
        assert(null != arr);
        int midd;
        if((end - start) > INSERT_SORT){
            while(start < end){
                midd = partition3(arr, start, end);
                partitionSort5(arr, start, midd - 1);
                start = midd + 1;
            }
        }else{
            insertSort(arr);
        }
    }

以上全是本人自己对于快速排序的总结,如果有什么不恰当或者错误的地方,还望各位批评指正!

<think>嗯,用户问的是Java中Collections.sort()Arrays.sort()的区别。我得先回忆一下这两个方法的用途和实现。Collections.sort()应该是用来对集合进行排序的,比如List,而Arrays.sort()是针对数组的。那它们的底层实现有什么不同呢? 首先,Arrays.sort()处理的是数组,而数组可以包含基本类型和对象类型。对于基本类型,比如int、long等,Arrays.sort()使用的是双轴快速排序算法,这可能是因为快速排序在平均情况下性能较好,而且不需要稳定性。而对于对象数组,使用的是TimSort算法,这是一种稳定的排序算法,归并排序的优化版本,可以保持相等元素的相对顺序。稳定性在某些情况下很重要,比如当对象有多个排序键的时候。 然后是Collections.sort(),它操作的是List集合,比如ArrayList、LinkedList等。这个方法内部其实是将List转换为数组,然后调用Arrays.sort()来进行排序。所以对于底层实现来说,当使用Collections.sort()时,实际上也是用到了Arrays.sort()的TimSort算法,因为处理的都是对象类型。不过,LinkedList这种结构转换成数组可能会有性能上的影响,因为需要遍历链表复制元素到数组中,排序完再转换回去,这可能会影响效率。 另外,两者的参数有所不同。Collections.sort()接受一个List和一个可选的Comparator,而Arrays.sort()接受数组,并且对于对象数组,也可以有Comparator。对于基本类型数组,Comparator不是必须的,因为它们有自然的排序顺序,而对象数组可能需要Comparator来指定排序规则。 还有关于并行排序的问题,Java 8之后,Arrays.sort()引入了并行排序方法Arrays.parallelSort(),但Collections.sort()好像没有对应的并行版本,可能还是单线程的。不过用户的问题里没有提到这点,可能不需要深入讨论。 需要确认一下是否所有情况下,Collections.sort()都是调用Arrays.sort()。比如对于ArrayList,它的toArray()方法可能更高效,直接返回底层数组的拷贝,而LinkedList可能需要遍历。所以对于不同的List实现,Collections.sort()的性能可能会有差异,但用户可能更关心的是两者的用途和基本区别,而不是具体实现的细节。 总结的话,主要区别在于操作对象不同,一个是集合,一个是数组;底层算法在基本类型和对象类型处理上不同,以及稳定性方面的考虑。可能还需要提到Collections.sort()在内部转换List到数组的过程,导致对链表结构的性能影响。 有没有可能遗漏了什么?比如线程安全的问题?不过这两个方法在排序时应该都不保证线程安全,需要外部同步。或者是否原地排序?是的,两者都是原地排序,会修改原数组或集合的顺序。 最后要确保用中文,结构清晰,分点说明,使用正确的LaTeX格式。比如提到算法的时候用双$符号包围,比如快速排序和TimSort。</think>Java中的`Collections.sort()`和`Arrays.sort()`都是用于排序的工具方法,但它们在**适用场景、底层实现**和**性能特点**上有明显区别。以下是分步解析: --- ### 1. **操作对象不同** - **`Arrays.sort()`** 用于对**数组**排序,支持: - 基本类型数组(如 `int[]`, `double[]`) - 对象数组(如 `String[]`, `Object[]`) ```java int[] arr = {3, 1, 2}; Arrays.sort(arr); // 对基本类型数组排序 String[] strArr = {"C", "A", "B"}; Arrays.sort(strArr); // 对对象数组排序 ``` - **`Collections.sort()`** 用于对**实现了`List`接口的集合**排序(如 `ArrayList`, `LinkedList`): ```java List<Integer> list = new ArrayList<>(Arrays.asList(3, 1, 2)); Collections.sort(list); // 对List集合排序 ``` --- ### 2. **底层算法不同** - **`Arrays.sort()`的底层实现** - **基本类型数组**(如 `int[]`): 使用**双轴快速排序(Dual-Pivot Quicksort)**,$$ \text{时间复杂度平均为 } O(n \log n)$$。 **不稳定排序**(相等元素可能交换顺序)。 - **对象数组**(如 `Object[]`): 使用**TimSort**(归并排序的优化变种),$$ \text{时间复杂度为 } O(n \log n)$$。 **稳定排序**(相等元素保持原顺序)。 - **`Collections.sort()`的底层实现** 内部先将`List`转换为数组,再调用`Arrays.sort()`进行排序: ```java // Collections.sort()源码简化 public static <T extends Comparable<? super T>> void sort(List<T> list) { Object[] a = list.toArray(); Arrays.sort(a); // 调用Arrays.sort() // 将排序后的数组写回原List } ``` 因此,对`List`的排序最终也使用**TimSort**(对象数组的排序算法)。 --- ### 3. **性能差异** - **对数组排序** `Arrays.sort()`直接操作数组,性能更高。 基本类型的快速排序通常比对象的TimSort更快(但牺牲稳定性)。 - **对集合排序** `Collections.sort()`需要将集合转为数组,排序后再写回集合。 对`LinkedList`等非连续存储的集合,转换过程会有额外开销。 --- ### 4. **稳定性对比** - **`Arrays.sort()`对对象数组稳定,对基本类型不稳定** 例如,对 `int[]` 排序时,相等元素可能交换顺序;但对 `String[]` 排序时保持顺序。 - **`Collections.sort()`始终稳定** 因为它最终调用`Arrays.sort()`的对象数组排序(TimSort)。 --- ### 5. **使用场景建议** 1. 若数据是**数组**,优先用`Arrays.sort()`。 2. 若数据是`List`集合,必须用`Collections.sort()`。 3. 若需要**稳定性**(如多条件排序),确保操作对象是引用类型。 --- ### 示例对比 ```java // 对基本类型数组(不稳定) int[] arr = {5, 2, 2, 8}; Arrays.sort(arr); // 可能改变相等元素的顺序 // 对对象数组(稳定) String[] strArr = {"apple", "banana", "Apple"}; Arrays.sort(strArr, String.CASE_INSENSITIVE_ORDER); // 相等元素保持原顺序 // 对List集合(稳定) List<Integer> list = Arrays.asList(5, 2, 2, 8); Collections.sort(list); // 稳定排序 ``` --- ### 总结 | 特性 | `Arrays.sort()` | `Collections.sort()` | |--------------------|-------------------------------------|--------------------------------| | **操作对象** | 数组(基本类型/对象类型) | `List`集合 | | **底层算法** | 快速排序(基本类型)/ TimSort(对象) | 内部调用`Arrays.sort()`(TimSort) | | **稳定性** | 基本类型不稳定,对象稳定 | 稳定 | | **性能** | 直接操作数组,更快 | 依赖集合类型(如`LinkedList`有转换开销) |
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值