问题描述:
设子数组a[0:k-1]和a[k:n-1]已排好序(0<=k<=n-1)。试设计一个合并这两个子数组为排好序的数组a[0:n-1]的算法。要求算法在最坏情况下所用的计算时间为O(n),且只用到O(1)的辅助空间。
思路:
首先用二分搜索算法在数组段a[k:n-1]中搜索a[0]的插入位置,即找到位置p使得a[p]<a[0]<=a[p+1]。数组段a[0:p]向左循环移位p-k+1个位置。此时,数组元素a[p]及其左边的所用元素均已排好序。对剩余的数组元素重复上述过程,直至剩下一个数组段,此时整个数组已排好序。
例int a[7]= {7,9 ,11,13,6,8,10}
k=4,a[0]在a[k:6]的插入位置为p=4; 将数组段a[0:p]循环左移p-k+1=4-4+1=1个位置得到
a[7]={6,7,9,11,13,8,10}
此时k=p+1=5.下一个要考察的元素为a[2]
然后查看a[2]在数组a[5:n-1]的插入位置p=5 数组段a[2:5]向左循环移位p-k+1=1个位置,此时数组变为
a[7]={6,7,8,9,11,13,10}
此时k=6,下一个要考察的元素为a[4]=11
然后查看a[4]在数组a[6:6]的插入位置为p=6,数组段a[4:6]向左循环移位6-6+1=1个位置,此时数组为
a[7]={6,7,8,9,10,11,13}
此时k=7>n-1,循环结束
代码如下:
#include <iostream>
using namespace std;
int binarysearch(int a[],int x,int left,int right)//二分搜索
{
int middle;
while(left<=right)
{
middle=(left+right)/2;
if(x==a[middle])
return middle;
if(x>a[middle])
left=middle+1;
else
right=middle-1;
}
if(x>a[middle])
return middle;
else
return middle-1;
}
void shiftleft(int a[],int s,int t,int k) //a[s,t]中元素循环左移k个位置
{
int i,j,temp;
for(i=0;i<k;i++)
{
temp=a[t];
for(j=t;j>s;j--)
a[j]=a[j-1];
a[s]=temp;
}
}
void mergefor(int a[],int k,int n)
{
int i=0,j=k;
int p;
while(i<j&&j<n)
{
p=binarysearch(a,a[i],j,n-1);
shiftleft(a,i,p,p-j+1);
i+=p-j+2;
j=p+1;
}
}
int main()
{
int a[10]={1,5,6,7,2,3,4,8,9,10};
int x,temp;
int i;
//temp=5;
//x=binarysearch(a,temp,0,3);
//shiftright(a,0,3,2);
mergefor(a,4,10);
for(i=0;i<10;i++)
cout<<a[i]<<' ';
//cout<<x;
return 0;
}