归并排序算法

本文深入解析了归并排序的原理和思路,包括2路归并排序的过程,采用递归方法实现分而治之。通过实例展示了如何从数组中间划分并进行两两归并,同时提供了C++代码实现。归并排序算法具有稳定性,空间复杂度为O(n),时间复杂度为O(nlogn)。
摘要由CSDN通过智能技术生成

归并排序

概述与思路

所谓归并,是指将两个或多个有序序列合并成一个新的有序序列。

默认的归并排序是指 2路归并排序

  • 即若待排序列有 n 个元素,将其视为 n 个长度为 1 的有序序列,两两归并后得到 ⌈n/2⌉ 个有序序列
  • 继续两两归并,最终得到长度为 n 的有序序列

例如 ⏯

mergesort

该图源于:

十大经典排序算法(动图演示) - 一像素 - 博客园 (cnblogs.com)

采用 递归 方法,整体思路为 分而治之

  • 由上而下,将待排序列递归地划分为左右两个子序列,直至子序列不可再划分为止(即每个子序列长度为 1 )
  • 由下而上,两两归并,最终合并成一个有序序列

代码CPP实现

递归划分,整体结构:

// 传入的 temp[] 是在主函数 main 内开辟的辅助数组,可以在递归栈中重复使用
void mergeSort(int arr[], int temp[],int low, int high) {
	if (low < high) {
		int mid = low + ((high - low) >> 1);	// 从数组中间位置划分,深度优先划分左侧,后右侧
		mergeSort(arr, temp, low, mid);
		mergeSort(arr, temp, mid + 1, high);
		merge(arr, temp, low, mid, high);		// 两两归并操作
	}
}

❗️ 注意:

  • int mid = low + ((high - low) >> 1);
    int mid = (low + high) / 2;
    

    当数组长度很大时,第一句可以避免溢出

  • 传入 temp[] 是为了 在 merge() 归并时使用,避免了在 merge()递归栈内反复开辟和删除辅助空间,后续代码注解⭕️

归并操作

void merge(int arr[],int temp[], int low, int mid, int high) {	
	for (int k = low; k <= high; k++)
		temp[k] = arr[k];				// 辅助数组temp[]赋值,用于比较,arr[]内交换
	int i = low, j = mid + 1, k = low;	// i为左侧子序列下标,j为右侧子序列下标,k为arr[]排好序的位置
	while (i <= mid && j <= high) {		// 两个子序列元素“交替” 比较,一直到某序列比较完毕
		if (temp[i] <= temp[j])			// 这个<= 决定了归并排序的稳定性
			arr[k++] = temp[i++];		// 先赋值,然后后移一位
		else
			arr[k++] = temp[j++];
	}
	while (i <= mid)					// 以下操作是剩余某有序子序列,追加到尾部
		arr[k++] = temp[i++];
	while (j <= high)
		arr[k++] = temp[j++];
}

❗️ 注意:

  • if (temp[i] <= temp[j])			
        arr[k++] = temp[i++];
    

    这句代码 if() 中的 <= 决定了归并排序算法是稳定的,即不会改变相同元素值的相对次序

  • 传入 temp[] ,在主函数内开辟额外数组,可以在递归栈中重复使用,避免了每次递归都要开辟和销毁空间,如:

    void merge(int arr[],int temp[], int low, int mid, int high) {
        int* temp = new int[high - low + 1];	// 开辟数组
        
    	for (int k = low; k <= high; k++)
    		temp[k] = arr[k];
    	int i = low, j = mid + 1, k = low;
    	while (i <= mid && j <= high) {
    		if (temp[i] <= temp[j])
    			arr[k++] = temp[i++];
    		else
    			arr[k++] = temp[j++];
    	}
    	while (i <= mid)
    		arr[k++] = temp[i++];
    	while (j <= high)
    		arr[k++] = temp[j++];
        
        delete[] temp;					// 销毁数组
    }
    

算法分析

  • 空间复杂度: O(n) ,辅助数组为 n 个单元,递归栈为 O(logn)
  • 时间复杂度:O(nlogn) ,每趟归并时间为 O(n) ,共需 ⌈log2n⌉
  • 稳定性:✔️

对比 2路归并排序,可以类比分析 k路归并排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值