1.要求2n个数的中位数,采用分治策略。每次划分后,都会去掉一半的数,只剩原来一半的数。
递推关系式为:T(n)=T(n/2)+O(1),由master定理,可得时间复杂度为O(logn)。
#include<cstdio>
#include<iostream>
#define N 1000000
using namespace std;
int a[N],b[N];
int i,n;
int getMin(int x,int y)//比较得到较小的数
{
if (x<y) return x;
return y;
}
int getMax(int x,int y)//比较得到较大的数
{
if (x>y) return x;
return y;
}
double getMedian(int arr[],int n)//得到中位数
{
if (n&1==1)//若为奇数个,中位数为arr[n/2];若为偶数个,中位数为(arr[(n/2)-1]+arr[n/2])/2
{
return arr[n/2];
}
else return (arr[(n/2)-1]+arr[n/2])/2.0;
}
double CalMedian(int a[],int b[],int n)
{
double m1,m2;
if (n==1)//若最后只剩2个数,中位数即为两个数的平均数
return (a[0]+b[0])/2.0;
if (n==2)//若最后只剩4个数,中位数即为(getMax(a[0],b[0])+getMin(a[1],b[1]))/2
{
return (getMax(a[0],b[0])+getMin(a[1],b[1]))/2.0;
}
m1=getMedian(a,n);
m2=getMedian(b,n);
if (m1==m2)//若两个数组中位数相等,直接返回m1
return m1;
if (m1<m2)//若m1<m2,n为偶数,搜索范围为(a+n/2-1,b);n为奇数,搜索范围为(a+n/2,b);
{
if (n&1==0)
return CalMedian(a+n/2-1,b,n/2+1);
else
return CalMedian(a+n/2,b,n/2+1);
}
else
{
if (n&1==0)
return CalMedian(b+n/2-1,a,n/2+1);
else
return CalMedian(b+n/2,a,n/2+1);
}
}
int main()
{
printf("输入数组长度n的大小:");
scanf("%d",&n);
printf("\n请如输入第一个数组的值:");
for (i=0;i<n;i++)
{
cin>>a[i];
}
printf("\n请输入第二个数组的值:");
for (i=0;i<n;i++)
{
cin>>b[i];
}
printf("\n两个数组的中位数是:");
cout<<CalMedian(a,b,n)<<endl;
return 0;
}
2.要求逆序数,采用分治策略。每次划分后,都会去掉一半的数。总逆序数=左半边逆序数+右半边逆序+两半边分别排序后的逆序数。 若需要排序A[p…q],则可以对半分成A[p…r]和A[r…q],然后将这有序的两部分合并。合并过程的时间复杂度为O(n)。
递推关系式为:T(n)=2T(n/2)+O(n),由master定理,可得时间复杂度
为O(nlogn)。
#include<cstdio>
#include<iostream>
#define N 1000000
using namespace std;
int a[N],l[N],r[N],temp[N];
int i,n;
int mergeSort(int a[],int low,int high)
{
int mi=(high-low)/2;
int llen=(mi-low)+1;//左边的长度
int rlen=high-mi;//右边的长度
int i,j;
//memset(l,0,sizeof(l));
//memset(r,0,sizeof(r));
for (i=0;i<llen;i++)
{
l[i]=a[low+i];//记录左边的数
}
for (i=mi+1;i<=high;i++)
{
r[i-mi-1]=a[i];//记录右边的数
}
int ret=0;
int k=low;
i=0,j=0;
while(i<llen && j<rlen)//两个指针扫描比较大小,归并排序
{
if (l[i]<=r[j])
temp[k++]=l[i++];
else
{
temp[k++]=r[j++];
ret+=llen-i;
}
}
while(i<llen)//处理剩余的数
{
temp[k++]=l[i++];
}
while(j<rlen)
{
temp[k++]=r[j++];
}
return ret;
}
int CalReverseOrder(int a[],int low,int high)//计算逆序数
{
int ans=0;
if (low>=high)
{
return 0;
}
int mi=(low+high)/2;
ans+=CalReverseOrder(a,low,mi);//计算(low,mi)范围内的逆序数
ans+=CalReverseOrder(a,mi+1,high);//计算(mi+1,high)范围内的逆序数
ans+=mergeSort(a,low,high);//再加上归并排序后增加的逆序数
return ans;
}
int main()
{
printf("输入数组长度n的大小:");
scanf("%d",&n);
printf("\n请输入数组的值:");
for (i=0;i<n;i++)
{
cin>>a[i];
}
printf("\n逆序对的个数是:");
cout<<CalReverseOrder(a,0,n-1)<<endl;
return 0;
}