问题描述:数组a[0,mid-1]和a[mid,n-1]是各子有序的,对数组a[0,n-1]的两个子有序段进行合并,得到a[0,n-1]整体有序。要求空间复杂度为O(1)(注:al[i]元素是支持‘<'运算符的)。假定给定数组a={1,5,6,7,9,2,4,6,10,13,14},mid=5,a[0]~a[4]是有序的,a[5]~a[10]是有序的,合并后的数组为{1,2,4,5,6,7,8,9,10,13,14}。
假定数组中的子有序段都按升序排列,如上例所示。下面给出在这种情况下的实现思路;
由于限定空间复杂度为O(1),因此不能使用归并排序方法。最容易想到的是插入排序方法,但这种时间复杂度为O(n^2),空间复杂度为O(1),能满足题目要求,但是由于插入排序方法没有用到各子有序的条件,因此,这种算法并不是最好的算法,下面给出另外一种方法。
实现思路:
首先,遍历数组中下标为0~mid-1的元素,将遍历到的元素的值与a[mid]进行比较,当遍历到a[i](0<=i<=mid-1)时,如果满足a[mid]<a[i],那么交换a[i]与a[mid]的值。接着找到交换后的a[mid]在a[mid,num-1]中的具体位置,实现方法为:遍历a[mid~num-1],如果a[mid+1]<a[mid],那么交换a[mid]与a[mid+1]的位置。实现代码如下:
public static void findRightPlaceForMid(int[] a,int mid){
for(int i=mid;i<a.length-1;i++){
if(a[i+1]<a[i]){
int temp=a[i];
a[i]=a[i+1];
a[i+1]=temp;
}
}
}
public static void sort(int[] a,int mid){
for(int i=0;i<=mid-1;i++){
if(a[mid]<a[i]){
int temp=a[i];
a[i]=a[mid];
a[mid]=temp;
findRightPlaceForMid(a,mid);
}
}
}
当然,如果利用归并排序,也是可以实现的,具体实现代码如下:
public static int[] merge(int[] a,int[] b){
int aLength=a.length;
int bLength=b.length;
int[] arr=new int[aLength+bLength];
int aLeft=0;
int bLeft=0;
int aRight=aLength-1;
int bRight=bLength-1;
int tmp=0;
while(aLeft<=aRight && bLeft<=bRight){
if(a[aLeft]<b[bLeft])
arr[tmp++]=a[aLeft++];
else
arr[tmp++]=b[bLeft++];
}
while(aLeft<=aRight)
arr[tmp++]=a[aLeft++];
while(bLeft<=bRight)
arr[tmp++]=b[bLeft++];
return arr;
}