子数组合并算法之向右循环
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
i =0 j=5
第一步:a[0]不满足条件(a[p]<a[0<=a[p+1]])
i=1 j=5 p=null
第二步:a[1]满足条件:
i=2 j=6 p=4
第三步:a[3]满足条件:
..............................
..............................
以此类推,最终将得到合并的结果。
以下是代码分析:
体会:
算法有点难度,不过耐心的去理解,还好!
上网搜了半天,发现解决这个问题有两种基本的方式,一种是本文要讨论的向右循环,另一种我还没有看,等有时间了在补上。
算法的基本思想:
假设的两个子数组是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
1 | 3 | 5 | 7 | 9 | 2 | 4 | 6 | 8 |
第一步:a[0]不满足条件(a[p]<a[0<=a[p+1]])
1 | 3 | 5 | 7 | 9 | 2 | 4 | 6 | 8 |
第二步:a[1]满足条件:
1 | 2 | 3 | 5 | 7 | 9 | 4 | 6 | 8 |
第三步:a[3]满足条件:
1 | 2 | 3 | 4 | 5 | 7 | 9 | 4 | 6 | 8 |
..............................
..............................
以此类推,最终将得到合并的结果。
以下是代码分析:
#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]<<" "; } }
体会:
算法有点难度,不过耐心的去理解,还好!
相关文章推荐
- 【原创翻译】The Case for the Reduced Instruction Set Computer
- 通用权限管理系统中的分页解决方案
- Maven常用命令
- Minesweeper 1D
- mysql source 防止乱码
- 图片圆角处理
- 使用IntelliJ IDEA 编译开源的机器学习源码--Oryx
- 识云计算之感
- android apk 应用 重新签名 方法
- POJ 3191 The Moronic Cowmpouter
- Java的递归算法
- 对项目一的对文件处理
- 项目4扩展2--从文件中读入数据
- 使用Telnet命令收发E-mail
- DLL劫持技术详解(lpk.dll)
- linux IO子系统和文件系统读写流程
- RED HAT 系统使用yum网络源
- opengl 中render()的问题
- bash脚本应用
- js_day22--js DOM编程(window对象3+猜拳游戏)