2.3.1分治
纯翻译代码
void merge(ll A[],ll p,ll q,ll r)
{
ll n1,n2;
n1=q-p+1;
n2=r-q;
for(i=1;i<=n1;i++)
L[i]=A[p+i-1];
for(j=1;j<=n2;j++)
R[j]=A[q+j];
L[n1+1]=inf;
R[n2+1]=inf;
i=1;
j=1;
for(k=p;k<=r;k++)
{
if(L[i]<=R[j])
{
A[k]=L[i];
i=i+1;
}
else
{
A[k]=R[j];
j=j+1;
}
}
}
merge函数解析:
假设A数组的两部分(一个下标从p到q,一个从q+1到r)已经排序好了,现在将这两个排序好的部分数组再排序,每次比较两个子数组的头元素大小,小的插入,然后出队列。因为有哨兵的存在,所以一定能排完。
纯翻译代码
void mergesort(ll A[],ll p,ll r)
{
if(p<r)
{
ll q=(p+r)/2;
mergesort(A,p,q);
mergesort(A,q+1,r);
merge(A,p,q,r);
}
}
mergesort函数解析:
递归解决问题,对半分开数组,对每个子数组排序,再整合
总结:
分治法
- 将一个问题划分为若干个子问题。
- 递归的解决每一个子问题。
- 将子问题的解合并成为整个大问题的解。
归并排序
- 将一个数组分为两个子数组。
- 递归的对每一个子数组进行排序。
- 合并两个有序子数组。
时间复杂度 Θ(nlgn)
合并代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn=1000000;
ll n,A[maxn],L[maxn],R[maxn],i,j,k;
void merge(ll A[],ll p,ll q,ll r)
{
ll n1,n2;
n1=q-p+1;
n2=r-q;
for(i=1;i<=n1;i++)
L[i]=A[p+i-1];
for(j=1;j<=n2;j++)
R[j]=A[q+j];
L[n1+1]=inf;
R[n2+1]=inf;
i=1;
j=1;
for(k=p;k<=r;k++)
{
if(L[i]<=R[j])
{
A[k]=L[i];
i=i+1;
}
else
{
A[k]=R[j];
j=j+1;
}
}
}
void mergesort(ll A[],ll p,ll r)
{
if(p<r)
{
ll q=(p+r)/2;
mergesort(A,p,q);
mergesort(A,q+1,r);
merge(A,p,q,r);
}
}
int main()
{
scanf("%lld",&n);//n为数组长度
for(i=1;i<=n;i++)
scanf("%lld",&A[i]);
mergesort(A,1,n);
printf("%lld",A[1]);
for(i=2;i<=n;i++)
printf(" %lld",A[i]);
return 0;
}