Reference:
归并排序_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
其实有时候算法真正实现出来了再去看,也没当初自己觉得的那么难。
讲解用的C++,底下有用C实现了一下,其实没差。
具体的内容看顶部的视频,讲的很细。
归并排序名字已经说明了内涵,归指递归,将问题的规模缩小到只有一个元素时去解决,并指合并,将小的数组有序交叉合并,最后就能得到排序好的数组。
同样地,其实现也是分两步,递归(mergeSort)和合并(merge)。
mergeSort部分
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);//再排右边,不要重叠。
//注意这里所取的中点M和merge的中点要对应,只能把中点放在左边。
merge(arr,L,M,R);//合并两个分别有序的数组
}
merge部分
merge的功能是把一个数组按某一点拆成两个,再有序交叉合并。
比如1,4,2,3,5以2为分割点拆开,得到left[]={1,4,2},right[]={3,5},然后升序合并。
1比3小,所以第一个数是left的1.
然后4比3大,所以第二个数是right的3.
然后4比5小,所以第三个数是right的5.
此时right里的数已经用完了,就把left里剩下的数全部拷贝过去,把4,2拷贝过去
merge的结果就是1,3,5,4,2。
如果merge前的两个数组是有序的,那么merge完也是有序的。
void merge(int arr[],int L,int M,int R)
{
int left_size=M-L+1;//同样注意中间的元素不要重复,这里取左边的长一些,右边的短一些
int right_size=R-M;
int i=0,j=0,k=L;
int *left=new int[left_size];//创建两个辅助数组来存储分割前后的内容
int *right=new int[right_size];
while(i<left_size)
left[i++]=arr[k++];//拷贝前面的数字到left
while(j<right_size)
right[j++]=arr[k++];//拷贝后面的数字到right
i=j=0,k=L;
while(i<left_size&&j<right_size)//在两个数组都没遍历完之前,交叉合并
{
if(left[i]<right[j])//左边小,就取左边的数
{
arr[k]=left[i];
i++;k++;
}
else
{
arr[k]=right[j];
j++;k++;
}
}
if(i==left_size)//其中一个已经遍历完后,把另一个拷贝过去即可
while(j<right_size)
arr[k++]=right[j++];
else
while(i<left_size)
arr[k++]=left[i++];
delete []left;
delete []right;
}
最后实现的接口:
void mergeSort(数组名,起始下标,终止下标);
测试代码:
#include <iostream>
using namespace std;
void printArray(int a[],int L,int R)
{
while(L<=R)
cout<<a[L++]<<' ';
cout<<endl;
}
void merge(int arr[],int L,int M,int R)
{
int left_size=M-L+1;
int right_size=R-M;
int i=0,j=0,k=L;
int *left=new int[left_size];
int *right=new int[right_size];
while(i<left_size)
left[i++]=arr[k++];
while(j<right_size)
right[j++]=arr[k++];
i=j=0,k=L;
while(i<left_size&&j<right_size)
{
if(left[i]<right[j])
arr[k++]=left[i++];
else
arr[k++]=right[j++];
}
if(i==left_size)
while(j<right_size)
arr[k++]=right[j++];
else
while(i<left_size)
arr[k++]=left[i++];
delete []left;
delete []right;
}
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 argc, char const *argv[])
{
int arr[]={12,11,10,9,8,7,6,5,4,3,2,1,0};
mergeSort(arr,0,12);
printArray(arr,0,12);
return 0;
}
结果:
0 1 2 3 4 5 6 7 8 9 10 11 12
C语言实现
#include <stdio.h>
#include <stdlib.h>
void printArray(int [],int,int);
void merge(int [],int,int,int);
void mergeSort(int [],int,int);
int main(int argc, char const *argv[])
{
int arr[]={12,11,10,9,8,7,6,5,4,3,2,1,0};
mergeSort(arr,0,12);
printArray(arr,0,12);
return 0;
}
void printArray(int a[],int L,int R)
{
while(L<=R)
printf("%d%c",a[L++],L==R?'\n':' ');
}
void merge(int arr[],int L,int M,int R)
{
int left_size=M-L+1;
int right_size=R-M;
int i=0,j=0,k=L;
int *left=(int*)malloc(sizeof(int)*left_size);
int *right=(int*)malloc(sizeof(int)*right_size);
while(i<left_size)
left[i++]=arr[k++];
while(j<right_size)
right[j++]=arr[k++];
i=j=0,k=L;
while(i<left_size&&j<right_size)
{
if(left[i]<right[j])
arr[k++]=left[i++];
else
arr[k++]=right[j++];
}
if(i==left_size)
while(j<right_size)
arr[k++]=right[j++];
else
while(i<left_size)
arr[k++]=left[i++];
free(left);
free(right);
}
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);
}