排序算法:归并排序

排序算法:归并排序

思想:分治。先将子序列排好序后合并,区别于快速排序的先分割后排子序。

一、算法

递归地:将子序列两两合并为新的子序列,直到得到整个序列。
实现时需要额外的空间辅助(个人认为代码难写的点)。

合并两个有序子序列的伪代码(其实和合并链表一样):
Arr1, Arr2, MArr 分别代表需要合并的两个子序列,长度分别为L1、L2,以及存储合并后的序列,长度为L1+L2。

i <- 0, j <- 0, k <- 0   // 初始化三个数组的下标的指针
while i < L1 and j < L2   // 当两个子数组指针都还没有指到尾部
	if Arr1[i] <= Arr2[j]  // 将当前小的元素加入到合并数组中,更新指针
		MArr[k] <- Arr1[i]
		i <- i+1
		k <- k+1
	else
		MArr[k] <- Arr2[j]
		j <- j+1
		k <- k+1
while i < L1     // 将剩余元素加入进合并数组
	MArr[k] <- Arr1[i]
	i <- i+1
	k <- k+1
while j < L2
	MArr[k] <- Arr2[j]
	j <- j+1
	k <- k+1

二、代码实现

#include <iostream>
using namespace std;

void merge(int Arr1[], int L1, int Arr2[], int L2, int MArr[]) { // 合并函数 
    int i = 0, j = 0, k = 0;
    while (i < L1 && j < L2) {
        if (Arr1[i] <= Arr2[j]) {
            MArr[k] = Arr1[i];
            i++;
            k++;
        }
        else {
            MArr[k] = Arr2[j];
            j++;
            k++;
        }
    }
    while (i < L1) {
        MArr[k] = Arr1[i];
        i++;
        k++;
    }
    while (j < L2) {
        MArr[k] = Arr2[j];
        j++;
        k++;
    }
}


void MergeSort(int Arr[], int n) {  // 归并排序
    if (n < 2) {  // 终止条件:单个元素直接返回
        return;
    }
    const int half_n = n / 2;
    int* Arr1 = new int[half_n];  // 创建辅助空间存储子数组,然后就可以将后序合并好的数组存储到input数组中
    int* Arr2 = new int[n - half_n];
    for (int i = 0; i < half_n; i++) {
        Arr1[i] = Arr[i];
    }
    for (int i = half_n; i < n; i++) {
        Arr2[i - half_n] = Arr[i];
    }

    MergeSort(Arr1, half_n);  // 子数组递归调用排好序后
    MergeSort(Arr2, n - half_n);

    merge(Arr1, half_n, Arr2, n-half_n, Arr);  // 合并子数组

    delete[] Arr1;
    delete[] Arr2;
}



int main() {
    int A[8] = {6,10,13,5,8,3,2,11};
    MergeSort(A, 8);
    for (int i = 0; i < 8; i++) {
        cout << A[i] << ' ';
    }
}

三、分析

在每次排序都额外需要拷贝一份子数组,空间复杂度为Θ(n)\Theta(n)Θ(n)
每次归并都是将长度平半分的数组合并,且需要遍历一遍,即T(n)=2T(n/2)+Θ(n)T(n)=2T(n/2)+\Theta(n)T(n)=2T(n/2)+Θ(n),可知时间复杂度为Θ(nlgn)\Theta(nlgn)Θ(nlgn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值