当前位置:首页 > 算法 > 正文内容

【算法】归并排序

亿万年的星光8个月前 (05-21)算法89190

一、基本思想

归并排序的核心思想是将两个已经有序的子序列合并成一个有序序列。整个过程分为两个主要步骤:


 1.分解:将待排序的序列不断二分,直到每个子序列只包含一个元素(此时自然有序) 

 2.合并:将两个有序的子序列合并为一个有序序列


注意1:若将两个有序表合并成一个有序表,称为2-路归并。

注意2:归并排序则类似于二叉树的后序遍历:它会持续划分区间,直到区间内元素有序,然后利用额外空间对元素进行排序,并将它们合并回原区间,直至整个序列有序。这个过程中,划分区间相当于达到树的最底层,而归并排序则相当于从树的底层开始向上遍历。

二、算法步骤

1.分解阶段:

  • 将长度为n的序列分成两个长度为n/2的子序列

  • 递归地对这两个子序列进行归并排序

  • 直到子序列长度为1(此时已经有序)

2.合并阶段:

  • 申请空间,大小为两个已排序子序列之和

  • 设定两个指针,分别指向两个子序列的起始位置

  • 比较两个指针所指的元素,选择较小的放入合并空间,并移动指针到下一位置

  • 重复上一步直到某一指针超出子序列范围

  • 将另一子序列的剩余元素直接复制到合并序列的末尾



动图如下:


三、时间复杂度

  • 最优情况:O(n log n)

  • 最坏情况:O(n log n)

  • 平均情况:O(n log n)

归并排序的时间复杂度始终是O(n log n),因为它总是将序列分成两半,需要进行log₂n次分解,每次合并操作的时间复杂度为O(n)。


四、空间复杂度

归并排序需要额外的空间来存储临时合并的数组,因此其空间复杂度为O(n)。


五、稳定性

归并排序是稳定的排序算法,因为在合并过程中,当两个元素相等时,可以保证左边的元素先被放入结果数组中。



六、优缺点


优点:


  • 时间复杂度稳定为O(n log n)

  • 适用于大规模数据排序

  • 稳定排序算法


缺点:


  • 需要额外的存储空间(非原地排序)

  • 对于小规模数据排序效率可能不如简单排序算法


【参考代码】

// s - 当前子序列的起始下标
// t - 当前子序列的结束下标
//a[]:待排序的原始数组(全局变量)
//r[]:临时数组,用于合并时存储中间结果(全局变量)
void msort(int s,int t){
	// 递归终止条件:当子序列只有一个元素时直接返回 
	if(s==t)
		return;
	int mid =(s+t)/2;
	msort(s,mid);  //分解左序列 
	msort(mid+1,t); //分解右序列
	
	int i=s;// 左序列起始指针
    int j = mid + 1; // 右序列起始指针
    int k = s;      // 临时数组的指针
	// 比较两个子序列的元素,按顺序放入临时数组
	while(i<=mid && j<=t){
        if(a[i] < a[j]) {  // 左序列元素较小
            r[k] = a[i];   // 放入临时数组
			k++;
			i++; 
        } else {           // 右序列元素较小
            r[k] = a[j];   // 放入临时数组
			k++;
			j++;
		}
	} 
    // 处理左序列剩余元素(如果有)
	while(i<=mid){
		r[k]=a[i];
		k++;
		i++;
	} 
    // 处理右序列剩余元素(如果有)
	while(j<=t){
		r[k]=a[j];
		k++;
		j++;
	} 
	// 将排序好的临时数组复制回原数组
	for(int i=s;i<=t;i++){
		a[i]=r[i];
	}
	
}






    扫描二维码推送至手机访问。

    版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

    分享给朋友:

    相关文章

    【贪心】----找零钱问题

    一、找零钱问题例题1:有 1 元,5元,10元,20元,100元,200元的钞票无穷多张。现在使用这些钞票支付X元,最少需要多少张钞票。X = 628最佳支付方法:3张200块的,1张20块的,1张5...

    【排序】----冒泡排序

    【排序】----冒泡排序

    1.基本思想两个数比较大小,较大的数下沉,较小的数冒起来。2.过程·每次比较相邻的两个数,如果第二个数小,就交换位置。(升序或降序)·然后两两比较,一直到比较最后的数据。最终最小(大)数被交换到开始(...

    【贪心】区间覆盖

    【贪心】区间覆盖

    【题目描述】给定一个长度为m的区间,再给出n条线段的起点和终点(本题考虑闭区间),求最少使用多少线段可以将整个区间完全覆盖。【输入】第一行是区间长度m。第二行是n,表示有n个可选区间。后面跟着n行数据...

    【图论】迪杰斯特拉算法

    【图论】迪杰斯特拉算法

    迪杰斯特拉算法是由荷兰计算机科学家艾兹赫尔・迪杰斯特拉于 1956 年提出的单源最短路径算法,用于求解带权有向、 无向图中,从一个源节点到其余所有节点的最短路径问题(要求图中所有边的权值非负)。一、核...

    图论—拓扑排序

    前序文章:拓扑排序 - C++目录 - 青少年编程知识记录一、简述拓扑排序是针对 有向无环图(DAG, Directed Acyclic Graph) 的一种排序算法,其核心目标是...

    【图论】弗洛伊德算法(Floyd)

    【图论】弗洛伊德算法(Floyd)

    一、算法说明Floyd 算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与 Dijkstra 算法类似。 该算法名称以创始人之一、1978 年图灵奖获得者、斯坦福...