问题描述:设子数组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; }
子数组合并
最新推荐文章于 2021-03-20 19:41:36 发布