归并排序(自我理解):
就是将数组分小,小到长度为2(或者为1)的数组,先解决两个数的排序,然后将长度为2的数组两个连接起来变成长度为4(在连接的过程中有排序),然后两个长度为4的数组相连变成长度为8(相连时仍然排序,但复杂度是0(n)哦),依次往下。
总的来说就是分小,分到足够小时开始排序并,然后以排序的部分开始变大,变到和原来一样大时就排好了
下面时盗来的原理图。
下面是代码,上面的过程是在原数组中完成的,只是已排序的部分逐渐变大,未排序的部分逐渐变小
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<list>
#include<iterator>
#include<stack>
using namespace std;
#define ll long long int
#define ull unsigned long long int
#define e 2.718281828459
#define INF 0x7fffffff
#pragma warning(disable:4996)
#define pf printf
#define sf scanf
#define max(a,b) (a)>(b)?(a):(b);
#define min(a,b) (a)<(b)?(a):(b);
#define pi acos(-1.0);
#define eps 1e-9;
#define MAX 1000000+10
#include <queue>
void Mergesort(int left[], int lena, int right[], int lenb, int sum[]);
void link(int left[], int lena, int right[], int lenb, int temp[]);
int a[21] = {12,15,18,14,16,38,55,11,13,22,78,26,2,3,5,4,7,8,1,6,53 };
int temp[21];//记录每一次的段排序,减去了在link()函数中动态申请的时间
int main(void) {
Mergesort(a, 10, a+10, 11, temp);//将a一分为二a[1]....a[9],a[10]......a[20]
for (int i = 0; i < 20; i++)
pf("%d ", a[i]);
pf("\n");
system("pause");
return 0;
}
void link(int left[], int left_len, int right[], int right_len,int temp[]) {
/*
函数功能:将排好序的left段和right段按排好序的状况连接,他们的状况保存在temp数组中
*/
int i=0, j=0, k=0;
while (i < left_len&&j < right_len) {
if (left[i] < right[j])
temp[k++] = left[i++];
else
temp[k++] = right[j++];
}
while (i < left_len)
temp[k++] = left[i++];
while (j < right_len)
temp[k++] = right[j++];
for (int i = 0; i < left_len + right_len; i++) {//将排序好的段重新输入原数组,因为之后temp数组还要一直变化,直到最后一次即21个元素都排好序时就和原数组一样了
left[i] = temp[i];//之前没有将排序好的段输入数组中导致递归时temp数组被改动,无法得到正确结果
}
}
void Mergesort(int left[],int lena,int right[],int lenb,int sum[]) {
if (lena<=2&&lenb<=2) {//a[]于b[]的长度永远相差 1,达到一个为1 一个为2时进入(若总个数为奇数个,若为偶数个时,两段都为长度都为2时进入)
if (lena == 2) {
int max = left[0] > left[1] ? left[0] : left[1];
int min = left[0] < left[1] ? left[0] : left[1];
left[0] = min;
left[1] = max;
}
if (lenb == 2) {
int max = right[0] > right[1] ? right[0] : right[1];
int min = right[0] < right[1] ? right[0] : right[1];
right[0] = min;
right[1] = max;
}
}
else {
int lenl = lena / 2;
int lenr = lena - lenl;
Mergesort(left, lenl, left + lenl, lenr,sum);
int lenl2 = lenb / 2;
int lenr2 = lenb - lenl2;
Mergesort(right, lenl2, right + lenl2, lenr2, sum+lena);
}
link(left, lena, right, lenb, sum);
}
重新思索后改了一下,将递归推到了长度为1的数组(之前是长度为2和1)
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<list>
#include<iterator>
#include<stack>
using namespace std;
#define ll long long int
#define ull unsigned long long int
//#define e 2.718281828459
#define INF 0x7fffffff
#pragma warning(disable:4996)
#define pf printf
#define sf scanf
#define max(a,b) (a)>(b)?(a):(b);
#define min(a,b) (a)<(b)?(a):(b);
#define pi acos(-1.0);
#define eps 1e-9;
#define MAX 1000000+10
#include <queue>
ull Mergesort(int ar[], int len, int sum[]);
ull link(int left[], int lena, int right[], int lenb, int temp[]);
int a[21] = {12,15,18,14,16,38,55,11,13,22,78,26,2,3,5,4,7,8,1,6,53 };
int temp[21];//记录每一次的段排序,减去了在link()函数中动态申请的时间
int main(void) {
ull ans = 0;
for (int i = 0; i < 20; i++)
pf("%3d ", a[i]);
pf("\n");
ans=Mergesort(a, 21, temp);//将a一分为二a[1]....a[9],a[10]......a[20]
for (int i = 0; i < 20; i++)
pf("%3d ", a[i]);
pf("\n%d\n",ans);
system("pause");
return 0;
}
ull link(int left[], int left_len, int right[], int right_len,int temp[]) {
/*
函数功能:将排好序的left段和right段按排好序的状况连接,他们的状况保存在temp数组中
*/
int i=0, j=0, k=0;
ull ans = 0;
while (i < left_len&&j < right_len) {
if (left[i] < right[j])
temp[k++] = left[i++];
else
temp[k++] = right[j++],ans++;//只要right部分的往前添,就相当于交换,从右边交换到了左边
}
while (i < left_len)
temp[k++] = left[i++],ans++;//只要left部分的往后添,就相当于交换过,从左边交换到了右边
while (j < right_len)
temp[k++] = right[j++];
for (int i = 0; i < left_len + right_len; i++) {//将排序好的段重新输入原数组,因为之后temp数组还要一直变化,直到最后一次即21个元素都排好序时就和原数组一样了
left[i] = temp[i];//之前没有将排序好的段输入数组中导致递归时temp数组被改动,无法得到正确结果
}
return ans;
}
ull Mergesort(int ar[],int len,int sum[]) {
//if (lena<=2&&lenb<=2) {//a[]于b[]的长度永远相差 1,达到一个为1 一个为2时进入(若总个数为奇数个,若为偶数个时,两段都为长度都为2时进入)
// if (lena == 2) {
// int max = left[0] > left[1] ? left[0] : left[1];
// int min = left[0] < left[1] ? left[0] : left[1];
// left[0] = min;
// left[1] = max;
// }
//
// if (lenb == 2) {
// int max = right[0] > right[1] ? right[0] : right[1];
// int min = right[0] < right[1] ? right[0] : right[1];
// right[0] = min;
// right[1] = max;
//
// }
//
//}
if (len == 1)
return 0;
else {
ull ans = 0;
int lenl = (len+1) / 2;
int lenr = len - lenl;
Mergesort(ar, lenl,sum);
Mergesort(ar+lenl, lenr, sum+lenl);
ans+=link(ar, lenl, ar+lenl, lenr, sum);
return ans;
}
}