【分治算法】&【递归算法】归并排序(详细解析)

9 篇文章 1 订阅
本文深入介绍了归并排序的原理,包括其O(nlogn)的时间复杂度和稳定性。通过详细步骤解析,展示了如何将数组一分为二并使用特定的排序函数merge进行合并。代码示例分别使用C++和Python展示归并排序的完整流程,强调了分治算法在排序中的应用。此外,文章还探讨了归并排序与快速排序的比较,以及在实际编程中使用内置排序函数的情况。
摘要由CSDN通过智能技术生成


前言

归并排序主要学的就是方法,它的时间复杂度 O ( n l o g n ) O(nlog n) O(nlogn),非常快且稳定,这时,有同学有可能要说了:快速排序时间复杂度也是 O ( n l o g n ) O(nlogn) O(nlogn)呀!这里的归并排序快速排序好在它很稳定,而快速排序它是不稳定的最坏情况达到 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n),而归并排序非常稳定,最坏情况 O ( n l o g n ) O(nlogn) O(nlogn),这就是学归并排序的原因啦!当然不止这个原因
如果说你想用编译器里面的sort()函数进行排序的话,也是 O ( n l o g n ) O(nlogn) O(nlogn),所谓排序,对于我们来说可以锻炼我们的思维方式,这就是另外一个原因啦!


过程

让我们一起来模拟一下归并排序实现的思想过程吧!

要弄好归并排序,必须要了解它的过程,俗话说得好饮水思源就是这个意思,我们学归并排序必须要学会它的运行过程

很显然,看了标题就知道归并排序需要递归分而治之,这也就是分治算法,假如这个数组为,即 a r r = 7 , 6 , 9 , 3 , 1 , 5 , 2 , 4 arr = 7,6,9,3,1,5,2,4 arr=7,6,9,3,1,5,2,4
它的过程如下:

首先,这是一个数组,当然这是无序
在这里插入图片描述
紧接着,我们需要 “啪嗒” “啪嗒” 啪嗒一下,把它一分为二,去处理两边的排序
在这里插入图片描述
完了过后就成这样了,线的长短代表递归层数,越长层数越前

这样,做重复的动作,把它分为每份两个,然后逐一去进行特定的排序,大概一分为二的代码如下 😃 :

C++

void mergeSort(int arr[],int l,int r){
	if(l>=r) return;
	int m=(l+r)/2;
	mergeSort(arr,l,m);
	mergeSort(arr,m+1,r);
	merge(arr,l,m,r);// merge()函数为特定的排序函数
}

Python

def mergeSort(arr,l,r):
   if l < r: # 如果有元素
       m = int((l+r)/2)# 一分为二
       mergeSort(arr, l, m)
       mergeSort(arr, m+1, r)
       merge(arr, l, m, r)# 此为特定的排序之后会将说明

好了好了,讲一下代码,如果 l < = r l<=r l<=r也就是就只剩下一个元素了,就应该退出,不用继续二分,merge这个函数之后会讲,因为这就是我之前提到的特定的排序,它传入的值你有可能不懂,我来解释解释:
首先第一个参数就是数组值,这个不用管,第二三四个参数分别是:左指针,分隔下标,右指针。一般左指针和右指针指定的范围为 [ 0 , n / [0,n/ [0,n/层数 ] ] ],我将解释说明一下merge函数的运行功能,即特定的排序运行功能

特定的排序

分治分治,分而治之
首先,这个排序需要三个数组,一个是之前的数组 a r r arr arr,和左数组右数组,即 L L L R R R
它们的取值就是左指针到分隔下标,和分隔下标到右指针,代码操作如下 😃 :

C++

int n1=m-l+1,n2=r-m;
for(int i=0;i<n1;i++) L[i]=arr[l+i];
for(int i=0;i<n2;i++) R[i]=arr[m+1+i];

Python

n1 = m - l + 1
n2 = r- m
L = [0] * (n1)
R = [0] * (n2)
for i in range(0 , n1):
   L[i] = arr[l + i]
for j in range(0 , n2):
   R[j] = arr[m + 1 + j]

接下来,就得将这个排序的过程啦!大家激不激动呢?反正我是这样的!
左、右数组进行比较,较小值(当然这是升序)就 a r r arr arr数组里,如果有一个数组空了,就把另一个数组里的值拷贝进去,复制粘贴嘛~大家都懂,假设 t e m p = 8 , 4 , 5 , 7 , 1 , 3 , 6 , 2 temp=8,4,5,7,1,3,6,2 temp=8,4,5,7,1,3,6,2 我们已经做到了,这一步了:
在这里插入图片描述
分是分完了,现在得,治的过程是这样的:
在这里插入图片描述
那怎么排序呢?这是一个Problem,诶,有没有拼错?
所有图解在下面:

比较完之后的复制:

好的现在归并排序正式大功告成,思想一定要学会,引申出来的题也是数不胜数,大家加油

归并排序代码如下:

C++

#include<iostream>
#define MAX 20000000
using namespace std;
int arr[MAX],L[MAX],R[MAX],n;
int merge(int arr[],int l,int m,int r){
	int n1=m-l+1,n2=r-m;
	for(int i=0;i<n1;i++) L[i]=arr[l+i];
	for(int i=0;i<n2;i++) R[i]=arr[m+1+i];
	int i=0,j=0,k=l;
	while(i<n1&&j<n2){
		if(L[i]<=R[j])arr[k++]=L[i++];
		else arr[k++]=R[j++];
	}
	while(i<n1) arr[k++]=L[i++];
	while(j<n2) arr[k++]=R[j++]; 
}
void mergeSort(int arr[],int l,int r){
	if(l>=r) return;
	int m=(l+r)/2;
	mergeSort(arr,l,m);
	mergeSort(arr,m+1,r);
	merge(arr,l,m,r);
}
int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++) cin>>arr[i];
	mergeSort(arr,0,n-1);
	for(int i=0;i<n;i++) cout<<arr[i]<<" ";
	return 0;
}

Python

def merge(arr, l, m, r):
   n1 = m - l + 1
   n2 = r- m
   # 创建临时数组
   L = [0] * (n1)
   R = [0] * (n2)
   # 拷贝数据到临时数组 arrays L[] 和 R[]
   for i in range(0 , n1):
       L[i] = arr[l + i]
   for j in range(0 , n2):
       R[j] = arr[m + 1 + j]
   # 归并临时数组到 arr[l..r]
   i = 0     # 初始化第一个子数组的索引
   j = 0     # 初始化第二个子数组的索引
   k = l     # 初始归并子数组的索引
   while i < n1 and j < n2 :
       if L[i] <= R[j]:
           arr[k] = L[i]
           i += 1
       else:
           arr[k] = R[j]
           j += 1
       k += 1
   # 拷贝 L[] 的保留元素
   while i < n1:
       arr[k] = L[i]
       i += 1
       k += 1
   # 拷贝 R[] 的保留元素
   while j < n2:
       arr[k] = R[j]
       j += 1
       k += 1
def mergeSort(arr,l,r):
   if l < r: # 如果有元素
       m = int((l+r)/2)# 一分为二
       mergeSort(arr, l, m)
       mergeSort(arr, m+1, r)
       merge(arr, l, m, r)
arr = list(map(int,input().split(" ")))
n = len(arr)
print ("给定的数组")
for i in range(n):
   print ("%d" %arr[i],end=" ")
mergeSort(arr,0,n-1) # 参数分别为arr列表,左指针,右指针
print ("\n\n排序后的数组")
for i in range(n):
   print ("%d" %arr[i],end=" ")

看到这里了,还不点赞+收藏??? 😃 😉 😉

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值