排序算法介绍(五)归并排序

0. 简介

归并排序(Merge Sort)是一种分治思想的应用,它将待排序的数组不断拆分成小数组,直到每个小数组只有一个元素,然后将小数组两两合并,直到最终得到有序的数组。


1. 归并排序的实现

归并排序的基本思想:

  1. 分解:将待排序的数组从中间分成两部分,递归地对左右两部分进行分解,直到每个小数组只有一个元素,这时可以认为每个小数组是有序的。
  2. 解决:将两个有序的小数组合并成一个有序的数组。可以使用双指针法,比较两个数组的元素大小,按照从小到大的顺序将元素放入新的数组中。
  3. 合并:递归地将左右两个有序的数组合并成一个更大的有序数组,直到最终得到整个有序数组。

归并排序过程演示:


2. 归并排序时空间复杂度分析

归并排序的时间复杂度和空间复杂度分析如下:

  1. 时间复杂度:

    • 归并排序的时间复杂度是 O(n log n),其中 n 是待排序数组的长度。这是因为归并排序采用分治策略,每次将数组分成两半进行递归排序,然后再合并。在每一层递归中,需要对所有元素进行比较和移动,所以每层的时间复杂度是 O(n)。由于递归的深度是 log n,因此总的时间复杂度是 O(n log n)。
  2. 空间复杂度:

    • 归并排序的空间复杂度是 O(n)。这是因为在合并过程中,需要创建一个临时数组来存储两个有序子数组的元素。临时数组的大小与原数组相同,所以空间复杂度是 O(n)。需要注意的是,这个空间复杂度是额外的空间,不包括递归调用所使用的栈空间。如果考虑递归调用的栈空间,最坏情况下的空间复杂度将达到 O(n log n)。

综上所述,归并排序的时间复杂度是 O(n log n),空间复杂度是 O(n)。


3. 归并排序C语言代码

C代码实现:

cpp 复制代码
#include <stdio.h>  
  
// 合并两个有序数组  
void merge(int arr[], int l, int m, int r) {  
    int i, j, k;  
    int n1 = m - l + 1;  
    int n2 = r - m;  
  
    // 创建临时数组  
    int L[n1], R[n2];  
  
    // 将数据拷贝到临时数组  
    for (i = 0; i < n1; i++)  
        L[i] = arr[l + i];  
    for (j = 0; j < n2; j++)  
        R[j] = arr[m + 1 + j];  
  
    // 合并临时数组到原数组  
    i = 0;  
    j = 0;  
    k = l;  
    while (i < n1 && j < n2) {  
        if (L[i] <= R[j]) {  
            arr[k] = L[i];  
            i++;  
        } else {  
            arr[k] = R[j];  
            j++;  
        }  
        k++;  
    }  
  
    // 将剩余元素拷贝到原数组  
    while (i < n1) {  
        arr[k] = L[i];  
        i++;  
        k++;  
    }  
    while (j < n2) {  
        arr[k] = R[j];  
        j++;  
        k++;  
    }  
}  
  
// 归并排序函数  
void mergeSort(int arr[], int l, int r) {  
    if (l < r) {  
        int m = l + (r - l) / 2; // 计算中间位置  
        mergeSort(arr, l, m); // 对左半部分递归排序  
        mergeSort(arr, m + 1, r); // 对右半部分递归排序  
        merge(arr, l, m, r); // 合并左右两部分  
    }  
}  
  
// 测试代码  
int main() {  
    int arr[] = { 12, 11, 13, 5, 6, 7 };  
    int arr_size = sizeof(arr) / sizeof(arr[0]);   
    mergeSort(arr, 0, arr_size - 1); // 对数组进行归并排序  
    printf("Sorted array:\n");  
    for (int i = 0; i < arr_size; i++) {  
        printf("%d ", arr[i]);  
    }  
    printf("\n");  
    return 0;  
}

代码解释:

merge 函数:

  1. int n1 = m - l + 1;int n2 = r - m;:这两行代码计算两个子数组的长度。n1 是左子数组的长度,n2 是右子数组的长度。
  2. int L[n1], R[n2];:我们创建两个临时数组 LR 来存储左子数组和右子数组的元素。
  3. 接下来的两个循环将左子数组和右子数组的元素拷贝到临时数组 LR 中。
  4. 然后,我们使用三个指针 i, j, 和 k 来合并这两个有序的子数组。指针 ij 分别指向临时数组 LR 的当前元素,而指针 k 指向原数组 arr 的当前位置。
  5. 在合并的过程中,我们比较 L[i]R[j] 的值,并将较小的元素放入原数组 arr 中。这个过程会一直持续到我们遍历完 LR 中的所有元素。
  6. 最后,我们将剩余的元素(如果有的话)从 LR 拷贝到原数组 arr 中。

mergeSort 函数:

  1. if (l < r) { ... }:这个条件用于判断数组是否至少包含两个元素。如果只有一个元素或没有元素,那么数组已经是有序的,不需要进一步排序。
  2. int m = l + (r - l) / 2;:这行代码计算数组的中间位置。我们通过将数组的长度 (r - l) 除以 2 并加上起始索引 l 来得到中间位置 m
  3. mergeSort(arr, l, m);mergeSort(arr, m + 1, r);:这两行代码递归地对左子数组和右子数组进行排序。递归的终止条件是子数组的长度为 1 或 0。
  4. merge(arr, l, m, r);:当左子数组和右子数组都被排序后,我们使用 merge 函数将它们合并成一个有序的数组。

4. 归并排序代码运行结果

代码运行结果:

相关推荐
上弦月-编程2 分钟前
【C语言】函数栈帧的创建与销毁(底层原理)
c语言·开发语言
MATLAB代码顾问3 分钟前
混合粒子群-模拟退火算法(HPSO-SA)求解作业车间调度问题——附MATLAB代码
算法·matlab·模拟退火算法
Felven7 分钟前
C. Prefix Min and Suffix Max
算法
加农炮手Jinx7 分钟前
LeetCode 26. Remove Duplicates from Sorted Array 题解
算法·leetcode·力扣
加农炮手Jinx8 分钟前
LeetCode 88. Merge Sorted Array 题解
算法·leetcode·力扣
Hhy_11078 分钟前
【从零开始学习数据结构 ④】:栈 ——后进先出的艺术
c语言·数据结构·学习·visual studio
格林威8 分钟前
线阵工业相机:如何计算线阵相机的行频(Line Rate)?公式+实例
开发语言·人工智能·数码相机·算法·计算机视觉·工业相机·线阵相机
yueyue54311 分钟前
透过现象看本质:以fast_lio架构的整套算法的局部避障改为TEB算法为例深度探讨——如何成为一个合格的算法架构师?
算法·架构
梨花爱跨境11 分钟前
红人视频×A10算法:亚马逊转化率与流量闭环实战
算法
近津薪荼12 分钟前
C++ vector容器底层深度剖析与模拟实现
开发语言·c++