二路归并排序代码如下。
#include <iostream>
using namespace std;
//二路排序算法,书p17 正确性证明见p18-19
void merge(int *b,int p,int q,int r) //归并程序,线性时间复杂度
{
int i=0,j=0;
int L[18]={4,23,3,1,7,8,12,4,8,24,11,10,9,30,12,17,19,20};
int R[18]={4,23,3,1,7,8,12,4,8,24,11,10,9,30,12,17,19,20};
for (i=0;i<18;i++)
{
L[i]=1000;
R[i]=1000;
}
for (i=0;i<q-p+1;i++)
L[i]=b[p+i];
for(i=0;i<r-q;i++)
R[i]=b[q+i+1];
i=0;
int k=0;
for (k=p;k<=r;k++)
{
if (L[i]<=R[j])
{
b[k]=L[i];
i++;
}
else
{
b[k]=R[j];
j++;
}
}
}
void merge_sort(int* b,int p,int r) //递归,Ologn
{
int q=0;
if (p+1<r)
{
q=(p+r)/2;
merge_sort(b,p,q);
merge_sort(b,q+1,r);
merge(b,p,q,r);
}
}
int main()
{
int b[18]={4,23,3,1,7,8,12,4,8,24,11,10,9,30,12,17,19,20};
merge_sort(b,0,17);
for (int ii=0;ii<18;ii++)
cout<<b[ii]<<' ';
cout<<endl;
}
/*测试输出如下:
1 3 4 4 7 8 8 9 10 12 12 17 19 20 23 24 11 30
*/
一组数的逆序对满足如下公式。
A(p,r)=A(p,q)+A(q,r)+s(A(p,q)+A(q,r))
A(m,n)表示从序列中第m到n个数的逆序数个数。s(A,B)表示A,B序列之间的逆序数对数。s(A,B)与A,B内部顺序无关。
由此可对原二路归并排序的代码进行微调。
#include <iostream>
using namespace std;
//二路归并求逆序数
int merge(int *b,int p,int q,int r) //归并程序,线性时间复杂度
{
int i=0,j=0;
int temp=0; //temp即表示逆序数对数
int L[18]={4,23,3,1,7,8,12,4,8,24,11,10,9,30,12,17,19,20};
int R[18]={4,23,3,1,7,8,12,4,8,24,11,10,9,30,12,17,19,20};
for (i=0;i<18;i++)
{
L[i]=1000;
R[i]=1000;
}
for (i=0;i<q-p+1;i++)
L[i]=b[p+i];
for(i=0;i<r-q;i++)
R[i]=b[q+i+1];
i=0;
int k=0;
for (k=p;k<=r;k++)
{
if (L[i]<R[j])
{
b[k]=L[i];
i++;
temp=temp+j; //每次左边的数组记号移动的时候记录右边的编号累加
}
else
{
b[k]=R[j];
j++;
}
}
return temp;
}
int merge_sort(int* b,int p,int r) //递归,Ologn
{
int q=0;
if (p<r)
{
q=(p+r)/2;
return merge_sort(b,p,q)+merge_sort(b,q+1,r)+merge(b,p,q,r);
}
else return 0;
}
int main()
{
int b[18]={4,23,3,1,7,8,12,4,8,24,11,10,9,30,12,17,19,20};
cout<<merge_sort(b,0,17);
}