归并排序
先说一下,这个归并排序(版本一)是我自己的一些想法。简单地浏览了一下书本(《算法:C语言实现》(第三版)),实现方法并不一致。
但是这个算法我测试了一下,还行。
归并排序:分治法的思路。把一个待排序的数组(arr)分成两半(arrA和arrB)进行归并排序。在归并排序的过程中,arrA再分成两半……这个过程直到子数组无可再分。然后就回溯(应该是这么用这个名词),分别这些一对一对的细小的子数组进行插入排序……当这个过程回溯到arr的时候,由于arrA和arrB都已经是有序的子数组了,对arr的插入排序的工作量就相当小了。
版本一:
1 void 2 InsertSort(int arr[], int left, int right) 3 { 4 for (int i = left+1; i <= right; i++) { 5 int tmp = arr[i]; 6 for (int j = i-1; j >= 0 && arr[j] > tmp; j--) { 7 arr[j+1] = arr[j]; 8 arr[j] = tmp; 9 } 10 } 11 } 12 13 void 14 MergeSort(int arr[], int left, int right) 15 { 16 if (left == right) { 17 return; 18 } 19 20 int middle = (left + right) / 2; 21 22 MergeSort(arr, left, middle); 23 MergeSort(arr, middle+1, right); 24 25 InsertSort(arr, left, right); 26 }
版本二:读了Mark Allen Weiss的《数据结构与算法分析——C语言描述》(第二版),知道自己写的归并排序有分治的思想,但是在时间复杂度上其实还是维持插入排序的程度,是O(n^2),达不到O(nlogn)的程度。根据书本的知识,有了版本二的算法。
1 // 作合并操作 2 void 3 Merge(int arr[], int tmpArr[], int leftPos, int rightPos, int rightEnd) 4 { 5 int leftEnd = rightPos - 1; 6 int len = rightEnd - leftPos + 1; 7 int tmpPos = leftPos; 8 9 while (leftPos <= leftEnd && rightPos <= rightEnd) { 10 if (arr[leftPos] < arr[rightPos]) { 11 tmpArr[tmpPos++] = arr[leftPos++]; 12 } else { 13 tmpArr[tmpPos++] = arr[rightPos++]; 14 } 15 } 16 17 while (leftPos <= leftEnd) { 18 tmpArr[tmpPos++] = arr[leftPos++]; 19 } 20 while (rightPos <= rightEnd) { 21 tmpArr[tmpPos++] = arr[rightPos++]; 22 } 23 24 for (int i = 0; i < len; i++, rightEnd--) { 25 arr[rightEnd] = tmpArr[rightEnd]; 26 } 27 } 28 29 30 // 归并排序 31 void 32 MergeSort(int arr[], int tmpArr[], int left, int right) 33 { 34 if (left < right) { 35 36 int middle = (left + right) / 2; 37 38 MergeSort(arr, tmpArr, left, middle); 39 MergeSort(arr, tmpArr, middle+1, right); 40 41 Merge(arr, tmpArr, left, middle+1, right); 42 } 43 }