每日一排序:归并排序

本文介绍了归并排序的基本思想,步骤,以及C++和Python的代码实现。该算法采用分治策略,具有O(nlogn)的时间复杂度和稳定的排序特性,适用于对空间需求不高的有序数据排序。
摘要由CSDN通过智能技术生成

介绍

归并排序算法实质上是采用“分治”的思想来解决问题的。

思想

先将序列元素分解成单个元素,然后再两两比较形成有序序列。针对合合并后的有序序列,再次进行两两比较,直到生成一个有序序列为止。如图:

排序步骤

  1. 首先创建一个与原有序列空间一样大的序列空间,并用该空间来存放合并后的序列。
  2. 根据序列的起始和结束位置确定该序列的中间点,利用递归的形式分解序列,形成单独的元素。
  3. 设置两个指针,分别指向相邻两个序列的起始位置,比较两个指针指向的元素选择较小 / 较大的放入合并空间中,并移动已经放入合并空间的指针到下移位置,直到所有元素都是有序系列为止。

其中最后两个有序序列合并过程也被称为二路归并排序。通过归并排序的算法描述可知,该算法需要另辟空间来存储排序序列,所以其辅助空间均为 O ( n ) O(n) O(n) ,时间复杂度与快速排序算法相似,都是 O ( n log ⁡ n ) O(n\log n) O(nlogn) 在稳定性方面为稳定的排序算法。因此,当该排序数据量较大,且这些数据本身是有序的,对稳定性也有要求,且对于空间没有特殊要求时,可以采用该方法。

代码

C++版

#include <iostream>
using namespace std;

void merge(int arr[], int left, int mid, int right) {
    int i, j, k;
    int n1 = mid - left + 1;
    int n2 = right - mid;

    int L[n1], R[n2];

    for (i = 0; i < n1; i++)
        L[i] = arr[left + i];
    for (j = 0; j < n2; j++)
        R[j] = arr[mid + 1 + j];

    i = 0;
    j = 0;
    k = left;

    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 merge_sort(int arr[], int left, int right) {
    if (left < right) {
        int mid = left + (right - left) / 2;

        merge_sort(arr, left, mid);
        merge_sort(arr, mid + 1, right);

        merge(arr, left, mid, right);
    }
}

int main() {
    int arr[] = {9, 5, 2, 7, 1, 8, 3};
    int size = sizeof(arr) / sizeof(arr[0]);

    merge_sort(arr, 0, size - 1);
    
    for (int i = 0; i < size; i++)
        cout << arr[i] << " ";

    return 0;
}

这段代码定义了两个函数:mergemerge_sortmerge函数用于合并两个已排序的子数组,merge_sort函数用于将数组分成子数组并递归地对其进行排序。

merge函数中,我们首先计算两个子数组的长度,然后创建临时数组LR来存储这两个子数组的元素。接着,我们使用双指针来比较并合并两个子数组的元素,将结果存储到原始数组arr中。

merge_sort函数中,我们首先判断数组的左右边界,如果左边界小于右边界,则计算中间位置,并递归调用merge_sort函数来对左右两个子数组进行排序。最后,我们调用merge函数将两个有序子数组合并起来。

main函数中,我们定义了一个数组arr,然后调用merge_sort函数对其进行排序,并打印出排序后的结果。

Python版

def merge_sort(arr):
    if len(arr) <= 1:
        return arr
    
    mid = len(arr) // 2
    left_half = arr[:mid]
    right_half = arr[mid:]
    
    left_half = merge_sort(left_half)
    right_half = merge_sort(right_half)
    
    return merge(left_half, right_half)

def merge(left_half, right_half):
    merged = []
    left_index = 0
    right_index = 0
    
    while left_index < len(left_half) and right_index < len(right_half):
        if left_half[left_index] < right_half[right_index]:
            merged.append(left_half[left_index])
            left_index += 1
        else:
            merged.append(right_half[right_index])
            right_index += 1
            
    merged += left_half[left_index:]
    merged += right_half[right_index:]
    
    return merged

# 测试
arr = [4, 2, 5, 1, 3]
sorted_arr = merge_sort(arr)
print(sorted_arr)

总结

归并排序是辅助空间均为 O ( n ) O(n) O(n) ,时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn) 在稳定性方面为稳定的排序算法。如果对你有帮助,那就点个赞吧!球球辣

顺便点个关注, 给作者增加点储备粮吧pwp

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值