4.6.2归并排序及其两种实现方式(详解)
原理:将序列两两分组,将序列归并为[n/2]个组,组内单独排序;排序后,将这些组再两两归并,生成[n/4]个组,组内单独排序,以此类推;直到只剩下一个组。时间复杂度为O(nlogn).
例子:{66,12,33,57,64,27,18}
先分成{66,12},{33,57},{64,27},{18},对它进行排序
{12,66},{33,57},{27,64},{18},
接着合并 并 排序
{12,33,57,66},{18,27,64}
最后把这两个也合并了
{12,18,27,33,57,64,66}.
归并排序有两种实现方法:
1.非递归
//归并排序 非递归
#include <cstdio>
#include <math.h>
#include <algorithm>
using namespace std;
const int maxn = 100;
int n = 10;
void mergesort(int a[]);
void merge(int a[],int l1, int r1, int l2,int r2);
//这是主函数
int main(void)
{
int x[n] = {1,3,9,7,675,213,56,0,-10,13};
mergesort(x);
for(int i = 0 ; i < n ; i++)
{
printf("%d\n",x[i]);
}
return 0;
}
//利用c++ algorithm里的sort()
void mergesort(int a[])
{
//step为组内元素的个数如2,4,8;step/2为左子区间元素个数
for(int step = 2 ; step/2 < n ; step*=2)
{
//每step个元素一组,组内进行排序
for( int j = 0 ; j < n ; j+=step)
{
sort(a + j, a + int(min(n ,j + step - 1)));
}
}
}
2.递归
//归并排序 递归
#include <cstdio>
#include <math.h>
#include <algorithm>
using namespace std;
const int maxn = 100;
int n = 10;
void mergesort(int a[],int left,int right);
void merge(int a[],int l1, int r1, int l2,int r2);
int main(void)
{
int x[n] = {1,3,9,7,675,213,56,0,-10,13};
mergesort(x,0,9);
for(int i = 0 ; i < n ; i++)
{
printf("%d\n",x[i]);
}
return 0;
}
//将left 到 right之间的数据进行归并
void mergesort(int a[],int left,int right)
{
if(left < right)//只要left < right,也就是区间长度>=2
{
int mid = (left + right)/2;
mergesort(a,left,mid);//递归的算左子区间
mergesort(a,mid + 1,right);//递归的算右子区间
merge(a,left,mid,mid + 1,right);//把左子区间,右子区间合并并排序
}
}
void merge(int a[],int l1 ,int r1 , int l2 ,int r2)
{
int i = 0;
int j=0;
int k=0;
int b[maxn] = {0};
while(i + l1 <= r1 && j + l2 <= r2)//因为是其中一个放完,所以等号得取
{
if(a[l1 + i] < a[l2 + j])
{
b[k++] = a[l1 + i++];//把小的那个放入b中
}
else
{
b[k++] = a[l2 + j++];//把小的那个放入b中
}
}
// printf("xxxx");
while(i + l1 <= r1 ){ b[k++] = a[l1 + i++];}//把长的那个数组剩下的部分依次放入b中
while(j + l2 <= r2 ){ b[k++] = a[l2 + j++];}
for (int j = 0; j < k; j++) {
a[l1 + j] = b[j];//把排序后的结果传给a
}
}