java中常用排序工具类, 使用的算法是什么?什么,怎么还有组合模式参与?

Posted 洪宏鸿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中常用排序工具类, 使用的算法是什么?什么,怎么还有组合模式参与?相关的知识,希望对你有一定的参考价值。

排序我是认真的 🚇

所谓成长就是在人世间这个道场里的一场自我救赎与修行

Java中常用的排序工具类是Arrays.sort()和Collections.sort(),它们底层使用的是基于快速排序(quicksort)算法和归并排序(mergesort)算法的排序算法。

对于Arrays.sort()方法,其底层使用的是经过优化的快速排序算法,它是一种基于分治思想的排序算法,通过不断地把待排序的数组分割成较小的子数组进行递归排序,最终将这些子数组合并起来得到有序的结果。快速排序算法的时间复杂度为O(nlogn),它是目前使用最广泛的排序算法之一。

对于Collections.sort()方法,其底层使用的是归并排序算法,它也是一种基于分治思想的排序算法,它将待排序的数组不断划分成更小的子数组,对每个子数组进行排序后再将它们合并成一个有序的数组。归并排序算法的时间复杂度为O(nlogn),它具有稳定性和适用于大规模数据排序的优点。

需要注意的是,对于小规模数据排序,Arrays.sort()方法采用了插入排序(insertion sort)和选择排序(selection sort)的混合算法进行排序,而Collections.sort()方法则直接使用归并排序算法进行排序。

Arrays.sort()方法采用了一种优化的排序算法 组合模式 1+1>2

没想到吧, 设计模式竟然就在我们身边, 通过将各种排序进行组合, 得到在各个数据量中的优化解,
其实快速在小数据量的情况下, 并不是很快, 如果使用其他排序算法的情况下, 这个时候就要考虑排序算法的时间复杂度, 空间复杂度了
这个时候加上了我们的插入排序跟我们的选择排序, 简直是妙呀

Arrays.sort()方法采用了一种优化的排序算法,对于小规模数据使用了插入排序和选择排序的混合算法进行排序,其源码如下:

private static void sort(int[] a, int left, int right, int[] work, int workBase, int workLen) 
    // 当数组长度小于某个阈值时,使用插入排序或选择排序进行排序
    if (right - left < INSERTION_SORT_THRESHOLD) 
        insertionSort(a, left, right);
        return;
     else if (right - left < QUICKSORT_THRESHOLD) 
        binarySort(a, left, right, left + countRunAndMakeAscending(a, left, right));
        return;
    

    // 继续使用快速排序
    int pivot = medianOfThree(a, left, left + ((right - left) >> 1), right);
    int i = left;
    int j = right;
    int p = left;
    int q = right;
    while (true) 
        if (i <= j) 
            if (i != j) 
                if ((j - i) != 1) 
                    swap(a, i, pivot);
                
                if (a[i] <= pivot) 
                    i++;
                    continue;
                
                swap(a, i, j);
            
            j--;
        
        while (a[j] > pivot) 
            j--;
        
        while (i < j && a[i] <= pivot) 
            i++;
        
        if (i < j) 
            swap(a, i, j);
         else 
            break;
        
    

    // 将相等的元素移到数组中间
    int k = Math.min(i - left, p - left);
    vecswap(a, left, i - k, k);
    k = Math.min(q - j, right - j - 1);
    vecswap(a, i, right - k, k);

    // 对剩下的元素继续递归排序
    if ((k = i - left) > 1) 
        sort(a, left, i - 1, work, workBase, workLen);
    
    if ((k = right - j) > 1) 
        sort(a, j + 1, right, work, workBase, workLen);
    


可以看到,当待排序的数组长度小于某个阈值(默认为47)时,使用插入排序或选择排序进行排序,否则使用快速排序算法进行排序。

具体来说,当待排序的数组长度小于15时,使用插入排序进行排序;当待排序的数组长度大于等于15且小于47时,使用选择排序进行排序。选择排序的优点是不需要额外的空间来存储排序结果,且由于每次选择最小(或最大)的元素交换到数组的最前面,可以减少后续排序的比较次数。

需要注意的是,虽然插入排序和选择排序在时间复杂度上不如快速排序,但是对于小规模数据排序它们的时间复杂度较低,并且在实际应用中它们的表现可能比快速排序更好。

归并排序算法

归并排序是一种经典的排序算法,它基于分治思想,将待排序的数组分成两个子数组,对每个子数组进行排序后再将它们合并成一个有序的数组。

下面是归并排序的详细实现步骤:

  1. 分解数组:将待排序的数组从中间分成两个子数组,直到不能再分解为止。

  2. 排序子数组:对每个子数组进行排序,可以使用递归或非递归的方式。

  3. 合并数组:将排好序的子数组合并成一个有序的数组。

具体的实现方法可以是:

private static void mergeSort(int[] arr, int left, int right) 
    if (left < right) 
        // 1. 分解数组
        int mid = (left + right) / 2;
        mergeSort(arr, left, mid);
        mergeSort(arr, mid + 1, right);
        
        // 2. 排序子数组
        merge(arr, left, mid, right);
    


private static void merge(int[] arr, int left, int mid, int right) 
    // 定义左右两个子数组的开始和结束位置
    int leftStart = left;
    int leftEnd = mid;
    int rightStart = mid + 1;
    int rightEnd = right;
    
    // 计算左右两个子数组的长度
    int leftLength = leftEnd - leftStart + 1;
    int rightLength = rightEnd - rightStart + 1;
    
    // 创建左右两个子数组的临时数组
    int[] leftTemp = new int[leftLength];
    int[] rightTemp = new int[rightLength];
    
    // 将左右两个子数组复制到临时数组中
    for (int i = 0; i < leftLength; i++) 
        leftTemp[i] = arr[leftStart + i];
    
    for (int j = 0; j < rightLength; j++) 
        rightTemp[j] = arr[rightStart + j];
    
    
    // 3. 合并数组
    int i = 0;
    int j = 0;
    int k = leftStart;
    while (i < leftLength && j < rightLength) 
        if (leftTemp[i] < rightTemp[j]) 
            arr[k++] = leftTemp[i++];
         else 
            arr[k++] = rightTemp[j++];
        
    
    
    // 将左右两个子数组中剩余的元素复制到原数组中
    while (i < leftLength) 
        arr[k++] = leftTemp[i++];
    
    while (j < rightLength) 
        arr[k++] = rightTemp[j++];
    


在实现过程中,需要注意以下几点:

  1. 在合并数组时,需要使用额外的空间来存储左右两个子数组的临时数组。

  2. 在合并数组时,需要比较左右两个子数组中的元素,并将较小的元素先放入原数组中。

  3. 在合并数组时,需要将左右两个子数组中剩余的元素复制到原数组中。

  4. 在递归排序时,需要确定分解数组的位置,通常可以使用左右指针的方式来实现。

归并排序的时间复杂度为O(nlogn),它具有稳定性和适用于大规模数据排序的优点。但是,它需要额外的空间来存储临时数组,因此在实际应用中需要考虑内存的消耗。

Java 中List集合中自定义排序

/*
集合框架的工具类。
Collections:集合框架的工具类。里面定义的都是静态方法。

Collections和Collection有什么区别?
Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。
		它有两个常用的子接口,
		List:对元素都有定义索引。有序的。可以重复元素。
		Set:不可以重复元素。无序。

Collections是集合框架中的一个工具类。该类中的方法都是静态的
		提供的方法中有可以对list集合进行排序,二分查找等方法。
		通常常用的集合都是线程不安全的。因为要提高效率。
		如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。
*/

import java.util.*;

class Test3 
    public static void main(String[] args) 
        System.out.println("-------------sortDemo---------------");
        sortDemo();
        System.out.println("-------------maxDemo---------------");
        maxDemo();
        /**
         * -------------sortDemo---------------
         * [z, qq, zz, aaa, abcd, kkkkk]
         * -------------maxDemo---------------
         * [aaa, abcd, kkkkk, qq, z, zz]
         * max=zz
         */
    

    public static void sortDemo() 
        List<String> list = new ArrayList<String>();
        list.add("abcd");
        list.add("aaa");
        list.add("zz");
        list.add("kkkkk");
        list.add("qq");
        list.add("z");
        Collections.sort(list, new StrLenComparator());
        sop(list);
    

    public static void maxDemo() 
        List<String> list = new ArrayList<String>();

        list.add("abcd");
        list.add("aaa");
        list.add("zz");
        list.add("kkkkk");
        list.add("qq");
        list.add("z");
        Collections.sort(list);
        sop(list);
        String max = Collections.max(list);
        sop("max=" + max);
    

    public static void sop(Object obj) 
        System.out.println(obj);
    



/**
 * 比较器,先按字符长度然后按自然排序
 */
class StrLenComparator implements Comparator<String> 
    public int compare(String s1, String s2) 
        if (s1.length() > s2.length())
            return 1;
        if (s1.length() < s2.length())
            return -1;
        return s1.compareTo(s2);
    

  

以上是关于java中常用排序工具类, 使用的算法是什么?什么,怎么还有组合模式参与?的主要内容,如果未能解决你的问题,请参考以下文章

万字长文浅析Java集合中的排序算法

Java 常用排序

Java 中List集合中自定义排序

14Java常用类(StringBuffer)排序算法(冒泡排序选择排序插入排序快速排序)查找算法(二分查找)

常用排序算法及Java实现

常用排序算法的Java实现 - 1