您的位置:首页 > 其它

子数组合并算法之向右循环

2014-03-20 19:25 435 查看
        今天的算法课上,老师出了一道题:对两个已排好序的子序列,试设计一个合并算法使得算法的时间复杂度在最极端的情况下都小于等于O(n),可借助1个空间复杂度。

上网搜了半天,发现解决这个问题有两种基本的方式,一种是本文要讨论的向右循环,另一种我还没有看,等有时间了在补上。

       算法的基本思想:

假设的两个子数组是a[0:k-1]和a[k:n].

step1:取前一个数组的第一位,使用二分查找法找到他在后面数组的位置p。使得a[p]<a[0]<=a[p+1]

step2:获得p的位置后,开始向右循环位移p-(k-1)位,直到a[k-1]到达p的位置。

step3:因为原数组已经排好序,a[0](p前面的元素)都小于a[0],对剩余的元素重复操作即可。  

step4:最后只剩一个数组段的时候结束。

咱们直接以实例来阐述:                                       

                                           下标:  0       1        2      3      4      5     6      7      8

135792468
                                                                                                                                     i =0  j=5
                                          第一步:a[0]不满足条件(a[p]<a[0<=a[p+1]])

135792468
                                                                                                                                   i=1   j=5  p=null                                    

                                         第二步:a[1]满足条件:

123579468
                                                                                                                                  i=2  j=6  p=4
                                        第三步:a[3]满足条件:

                                                                                                            

1234579468
                                                                                                                                 

                                            ..............................

                                             ..............................

以此类推,最终将得到合并的结果。

以下是代码分析:

#include<iostream>
using namespace std;

//向右移动k位的函数,s  t代表a[s:t]

void shiftright(int a[],int s,int t, int k){
int i=0;
int j=0;
for( i=0;i<k;i++){//将第一个元素赋值给中间变量存储
int temp=a[t];
for( j=t;j>s;j--){//后一位变前一位
a[j]=a[j-1];
}
a[s]=temp;
}
}
//搜索x在代码块a[left,right]中的插入位置,返回下标
int binarysearch(int a[],int left,int right,int x){
int mid=0;
while(left<=right){
mid=left+(right-left)/2;
if(x==a[mid]){
return mid;
}
if(x>a[mid]){//递归调用
//return binarysearch(a,mid+1,right,x);
left=mid+1;
}
if(x<a[mid]){
//return binarysearch(a,left,mid-1,x);
right=mid-1;
}
}

if(x>a[mid]){
return mid;
}
else{
return mid-1;
}
}
//向右循环位移合并
void mergefor(int a[],int k,int length){
int i=0;
int j=k;
while(i<j&&j<length){
int position=binarysearch(a,j,length-1,a[i]);
shiftright(a,i,position,position-j+1);
j=position+1;
i+=position-j+2;//等价于i++。 j=position+1,i的位置向前移
}
}

void main(){
int a[9]={1,3,5,7,9,2,4,6,8};
int length=sizeof(a)/sizeof(a[0]);
cout<<"原数组是:"<<endl;
for(int i=0;i<length;i++){
cout<<a[i]<<"  ";
}
cout<<endl;
mergefor(a,5,length);
cout<<"排序后的数组是:"<<endl;
for(int i=0;i<length;i++){
cout<<a[i]<<" ";
}
}


体会:

算法有点难度,不过耐心的去理解,还好!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: