算法排序-归并排序

简介: Java系统提供的Arrays.sort函数。对于基础类型,底层使用快速排序。对于非基础类型,底层使用归并排序。请问是为什么?  答:这是考虑到排序算法的稳定性。

Java系统提供的Arrays.sort函数。对于基础类型,底层使用快速排序。对于非基础类型,底层使用归并排序。请问是为什么?
  答:这是考虑到排序算法的稳定性。对于基础类型,相同值是无差别的,排序前后相同值的相对位置并不重要,所以选择更为高效的快速排序,尽管它是不稳定的排序算法;而对于非基础类型,排序前后相等实例的相对位置不宜改变,所以选择稳定的归并排序。

在JDK的源码中也使用了归并排序,可见归并排序的重要性。我们一起来看看归并排序吧

归并排序

复杂度:
时间复杂度为:O(nlog₂n) 这是该算法中最好、最坏和平均的时间性能。
空间复杂度:O(n)

Java实现

图解

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。


img_dbee27c659a1bd5809275a2154143cb7.png
image.png
img_a29c0dd0186d1f8cef3c5ebdedf3e5a3.gif
image

代码

在比较代码中,我们需要定义三个下标。
分别指向当前数组要比较的左部分下标
分别指向当前数组要比较的右部分下标
当前数组要填充的元素

注意数组的边界。

@Slf4j
public class MergeSort {
    public static void main(String[] args) {
        //可随机生成数组
        int[] a =  {6,202,100,301,38,8,1};
        mergeInternal(a,0,a.length - 1);
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }
    }


    /**
     * 对数组进行归并
     *
     * @param arr
     * @param l,数组左边下标
     * @param r 数组右边下标
     */
    public static void mergeInternal(int[] arr,int l,int r){

        if (l >= r){
            //这里可以进行优化,在最后要比较的数组范围较小时候进行插入排序。
            return;
        }

        //两个下标的中间元素
        int mid = (l + r) / 2;

        //递归操作
        mergeInternal(arr, l, mid);
        mergeInternal(arr,mid + 1, r);

        // 当mid < mid+1时,代表已经排序过了
        if (arr[mid] < arr[mid + 1]){
            return;
        }
        
        merge(arr,l,mid,r);

    }

    /**
     *
     * @param arr
     * @param l //左下标
     * @param mid //中间位置
     * @param r 右下标
     */
    private static void merge(int[] arr,int l,int mid,int r) {
        //新建临时数组
        int[] temp = new int[(r - l)+1];

        for (int i = 0; i < temp.length; i++) {
            temp[i] = arr[ l + i ];
        }

        int i = l;
        int j = mid + 1;

        for (int k = l; k <= r; k++) {

            // 当左下标拍完序之后,进行右下标的排序
            if (i > mid){
                arr[ k ] = temp[j - l];
                j++;
            // 有下标全部排序完成                
            }else if (j > r){
                arr[ k ] = temp[i - l];
                i++;
            // 进行比较    
            }else if (temp[i - l ] < temp[j - l]){
                arr[k] = temp[i - l];
                i++;
            }else if (temp[i - l] >= temp[j - l]){
                arr[k] = temp[j - l];
                j++;
            }
        }

    }

}

优化部分

  1. 归并排序在进行数组排序之前,判断是否已经左右有序了,比较数组的mid下标与mid+1下标
  2. 在最后数据量分到较小的时候,进行插入排序。

最后

个人觉得归并排序是一个很重要的知识,在数据量足够大的时候进行排序还是要掌握一种高效稳定的排序方法。

相关文章
|
1月前
|
算法
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
|
1月前
|
搜索推荐 算法 Java
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
该博客文章通过UML类图和Java源码示例,展示了如何使用适配器模式将QuickSort类和BinarySearch类的排序和查找功能适配到DataOperation接口中,实现算法的解耦和复用。
20 1
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
|
1月前
|
算法 搜索推荐 Java
算法实战:手写归并排序,让复杂排序变简单!
归并排序是一种基于“分治法”的经典算法,通过递归分割和合并数组,实现O(n log n)的高效排序。本文将通过Java手写代码,详细讲解归并排序的原理及实现,帮助你快速掌握这一实用算法。
38 0
|
1月前
|
算法 关系型数据库 MySQL
揭秘MySQL中的版本号排序:这个超级算法将颠覆你的排序世界!
【8月更文挑战第8天】在软件开发与数据管理中,正确排序版本号对软件更新及数据分析至关重要。因MySQL默认按字符串排序版本号,可能出现&#39;1.20.0&#39;在&#39;1.10.0&#39;之前的不合理情况。解决办法是将版本号各部分转换为整数后排序。例如,使用`SUBSTRING_INDEX`和`CAST`函数从`software`表的`version`字段提取并转换版本号,再按这些整数排序。这种方法可确保版本号按逻辑正确排序,适用于&#39;major.minor.patch&#39;格式的版本号。对于更复杂格式,需调整处理逻辑。掌握此技巧可有效应对版本号排序需求。
103 3
|
1月前
|
数据采集 搜索推荐 算法
【高手进阶】Java排序算法:从零到精通——揭秘冒泡、快速、归并排序的原理与实战应用,让你的代码效率飙升!
【8月更文挑战第21天】Java排序算法是编程基础的重要部分,在算法设计与分析及实际开发中不可或缺。本文介绍内部排序算法,包括简单的冒泡排序及其逐步优化至高效的快速排序和稳定的归并排序,并提供了每种算法的Java实现示例。此外,还探讨了排序算法在电子商务、搜索引擎和数据分析等领域的广泛应用,帮助读者更好地理解和应用这些算法。
24 0
|
1月前
|
算法 搜索推荐
算法设计 (分治法应用实验报告)基于分治法的合并排序、快速排序、最近对问题
这篇文章是关于分治法应用的实验报告,详细介绍了如何利用分治法实现合并排序和快速排序算法,并探讨了使用分治法解决二维平面上的最近对问题的方法,包括伪代码、源代码实现及时间效率分析,并附有运行结果和小结。
|
1月前
|
存储 算法 Java
LeetCode初级算法题:反转链表+统计N以内的素数+删除排序数组中的重复项Java详解
LeetCode初级算法题:反转链表+统计N以内的素数+删除排序数组中的重复项Java详解
19 0
|
2月前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
【7月更文挑战第12天】归并排序是高效稳定的排序算法,采用分治策略。Python 实现包括递归地分割数组及合并已排序部分。示例代码展示了如何将 `[12, 11, 13, 5, 6]` 分割并归并成有序数组 `[5, 6, 11, 12, 13]`。虽然 $O(n log n)$ 时间复杂度优秀,但需额外空间,适合大规模数据排序。对于小规模数据,可考虑其他算法。**
66 4
|
2月前
|
算法 搜索推荐 C#
|
3月前
|
算法 Java 调度
Java数据结构与算法:拓扑排序
Java数据结构与算法:拓扑排序