1.数组al[0,mid-1]和al[mid,num-1]是各自有序的,对数组al[0,num-1]的两个子有序段进行merge,得到al[0,num-1]整体有序。要求空间复杂度为O(1)。注:al[i]元素是支持'<'运算符的。【2012年百度实习生招聘笔试题】

本题如果没有空间复杂度为O(1)的限制,则比较简单,以下代码就可以搞定:

备注c++:int *result = new int[a.length + b.length].

C代码  
  1. //两个有序数组的合并函数  
  2.      public static int[] MergeList(int a[],int b[])  
  3.      {  
  4.          int result[];    
  5.          result = new int[a.length+b.length];  
  6.                
  7.          int i=0,j=0,k=0;   //i:用于标示a数组    j:用来标示b数组  k:用来标示传入的数组  
  8.    
  9.          while(i<a.length && j<b.length)  
  10.              if(a[i] <= b[j]) {  
  11.                  result[k++] = a[i++];  
  12.              }else{  
  13.                  result[k++] = b[j++];  
  14.              }  
  15.    
  16.          return result;  
  17.          }  
  18.      }  

 

但是有了空间复杂度为O(1)的限制后,就不能新建result数组了

方案:

1、两个有序段位A和B,A在前,B紧接在A后面,找到A的第一个大于B[0]的数A[i], A[0...i-1]相当于merge后的有效段,在B中找到第一个大于A[i]的数B[j],对数组A[i...j-1]循环右移j-k位,/*使A[i...j-1]数组的前面部分有序。*/自己画个数组就清楚了。

2、如此循环merge。

3、循环右移通过先子段反转再整体反转的方式进行,复杂度是O(L), L是需要循环移动的子段的长度。

C代码  
  1. // 将有序数组a[begin...mid] 和 a[mid+1...end] 进行归并排序  
  2. void Merge(int *a , int begin , int end )  
  3. {  
  4.     int i , j , k;  
  5.     i = begin;  
  6.     j = 1 + ((begin + end)>>1);    //位运算的优先级比较低,外面需要加一个括号,刚开始忘记添加括号,导致错了很多次  
  7.     while(i <= end && j <= end && i<j)  
  8.     {  
  9.         while(i <= end && a[i] < a[j])  
  10.             i++;  
  11.         k = j;   //暂时保存指针j的位置  
  12.         while(j <= end && a[j] < a[i])  
  13.             j++;  
  14.         if(j > k)  
  15.             RotateRight(a , i , j-1 , j-k);   //数组a[i...j-1]循环右移j-k次  
  16.         i += (j-k+1);  //第一个指针往后移动,因为循环右移后,数组a[i....i+j-k]是有序的  
  17.     }  
  18. }  
  19.   
  20. void Reverse(int *a , int begin , int end )   //反转  
  21. {  
  22.     for(; begin < end; begin++ , end--)  
  23.         swap(a[begin] , a[end]);  
  24. }  
  25. void RotateRight(int *a , int begin , int end , int k)    //循环右移  
  26. {  
  27.     int len = end - begin + 1;  //数组的长度  
  28.     k %= len;  
  29.     Reverse(a , begin , end - k);  
  30.     Reverse(a , end - k + 1 , end);  
  31.     Reverse(a , begin , end);