前言
归并排序
主要学的就是方法,它的时间复杂度为
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=" ")
看到这里了,还不点赞+收藏??? 😃 😉 😉