归并排序-就地排序
题目要求:对归并排序进行修改,要求合并过程的空间复杂度为O(1)
解题思路:
假设a[beg, mid]和b[mid+1,end]是两段有序的子段,分别记做A和B,现要对其进行合并
1) 首先对A进行搜索,找到比B[0]大的第一个位置,记录为i,即A[0~i-1] < B[0],而A[i] > B[0];
2) 对B进行搜索,找到大于A[i]的第一个位置,记录为j,则B[0~j-1]<B[i]
3) 将A[i,mid], B[0,j-1] 进行旋转,使得B[0,j-1]旋转到左边,得到B[0,j-1] A[i, mid]
4)A[i, mid] B[j, end]是原来问题的一个子问题,继续上述1)-3)的步骤
下面是具体实现的代码:
1 #include <iostream> 2 3 using namespace std; 4 5 6 7 void reverse(int *array, int beg, int end) 8 9 { 10 11 while(beg < end) 12 13 { 14 15 int tmp = array[beg]; 16 17 array[beg] = array[end]; 18 19 array[end] = tmp; 20 21 ++beg; 22 23 --end; 24 25 } 26 27 } 28 29 30 31 void rotate(int *array, int beg, int end, int len) 32 33 { 34 35 len = len % (end - beg + 1); 36 37 reverse(array, beg, end - len); 38 39 reverse(array, end - len + 1, end); 40 41 reverse(array, beg, end); 42 43 } 44 45 46 47 void merge(int *array, int beg, int mid, int end) 48 49 { 50 51 int i = beg; 52 53 int j = mid + 1; 54 55 while(i <= end && j <=end && i < j) 56 57 { 58 59 while(i <= end && array[i] < array[j]) 60 61 { 62 63 ++i; 64 65 } 66 67 int k = j; 68 69 while(j <= end && array[j] < array[i]) 70 71 { 72 73 ++j; 74 75 } 76 77 if(j > k) // 注意这个条件 78 79 { 80 81 rotate(array, i, j-1, j-k); 82 83 } 84 85 86 87 i += (j -k + 1); 88 89 } 90 91 } 92 93 94 95 void mergeSort(int *array, int beg, int end) 96 97 { 98 99 if(beg == end) 100 101 return; 102 103 104 105 int mid = (beg + end) >> 1; 106 107 mergeSort(array, beg, mid); 108 109 mergeSort(array, mid + 1, end); 110 111 merge(array, beg, mid, end); 112 113 } 114 115 116 117 int main() 118 119 { 120 121 int array[] = {8, 7, 6, 5, 4, 3, 2, 1}; 122 123 int beg = 0; 124 125 int end = sizeof(array) / sizeof(int) - 1; 126 127 mergeSort(array, beg, end); 128 129 130 131 for(int i=beg; i<=end; ++i) 132 133 { 134 135 cout << array[i] << " "; 136 137 } 138 139 cout << endl; 140 141 142 143 return 0; 144 145 }