《算法导论》(CLRS)第三版 第1、2章总结(二)

5. 归并排序 (Merge Sort)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void print(int arr[], int n) {
 5     int i;
 6     for (i = 0; i < n; i++) {
 7         printf("%d ", arr[i]);
 8     }
 9     printf("\n");
10 }
11 
12 void merge(int arr[], int s, int n) {
13     int* L = (int*)malloc(s * sizeof(int));
14     int* R = (int*)malloc((n-s) * sizeof(int));
15     int i, j, k, t = n - s;
16     for (i = 0; i < s; i++) {
17         L[i] = arr[i];
18     }
19     for (j = 0; i < n; i++, j++) {
20         R[j] = arr[i];
21     }
22     i = j = k = 0;
23     while (i < s && j < t) {
24         if (L[i] <= R[j]) {
25             arr[k++] = L[i++];
26         } else {
27             arr[k++] = R[j++];
28         }
29     }
30     while (i < s) {
31         arr[k++] = L[i++];
32     }
33     while (j < t) {
34         arr[k++] = R[j++];
35     }
36     free(L), free(R);
37 }
38 
39 void merge_sort(int arr[], int n) {
40     if (n > 1) {
41         int s = n / 2, t = (n+1) / 2;
42         merge_sort(arr, s);
43         merge_sort(arr+s, t);
44         merge(arr, s, n); // [0, s) & [s, n)
45     }
46 }
47 
48 int main() {
49     int arr[10] = {1, 4, 2, 8, 5, 7, 9, 3, 0, 6};
50     int n = 10;
51     merge_sort(arr, n);
52     print(arr, n);
53     return 0;
54 }

上面程序中,merge_sort 的时间复杂度为 O(nlgn), 在合并时需要 O(n) 大小的额外空间。
下面给出一种原地归并排序的C语言代码:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void print(int arr[], int n) {
 5     int i;
 6     for (i = 0; i < n; i++) {
 7         printf("%d ", arr[i]);
 8     }
 9     printf("\n");
10 }
11 
12 void reverse(int arr[], int n) {
13     int i = 0, j = n-1;
14     while (i < j) {
15         int t = arr[i];
16         arr[i] = arr[j];
17         arr[j] = t;
18         i++, j--;
19     }
20 }
21 
22 void rotate(int arr[], int n, int k) {
23     reverse(arr, n-k);
24     reverse(arr+n-k, k);
25     reverse(arr, n);
26 }
27 
28 void merge(int arr[], int s, int n) {
29     int i = 0, j = s, k = s;
30     while (j < n) {
31         while (i < j && arr[i] <= arr[j]) i++;
32         if (i == j) break;
33         while (j < n && arr[j] < arr[i]) j++;
34         rotate(arr+i, j-i, j-k);
35         i += j-k, k = j;
36     }
37 }
38 
39 void merge_sort(int arr[], int n) {
40     if (n > 1) {
41         int s = n / 2, t = (n+1) / 2;
42         merge_sort(arr, s);
43         merge_sort(arr+s, t);
44         merge(arr, s, n); // [0, s) & [s, n)
45     }
46 }
47 
48 int main() {
49     int arr[10] = {1, 4, 2, 8, 5, 7, 9, 3, 0, 6};
50     int n = 10;
51     merge_sort(arr, n);
52     print(arr, n);
53     return 0;
54 }

 

6. 冒泡排序 (Bubble Sort)

 1 void bubble_sort(int arr[], int n) {
 2     int i, j;
 3     for (i = 0; i < n; i++) {
 4         for (j = n-1; j > i; j--) {
 5             if (arr[j] < arr[j-1]) {
 6                 int tmp = arr[j];
 7                 arr[j] = arr[j-1];
 8                 arr[j-1] = tmp;
 9             }
10         }
11     }
12 }

对其做一点小的优化,使得最好情况下时间复杂度为 O(n),平均情况下执行时间有所减少,但是不会改变平均情况和最坏情况下渐近复杂度的上界 O(n^2)。

 1 void bubble_sort(int arr[], int n) {
 2     int i, j;
 3     for (i = 0; i < n; i++) {
 4         int flag = 0;
 5         for (j = n-1; j > i; j--) {
 6             if (arr[j] < arr[j-1]) {
 7                 int tmp = arr[j];
 8                 arr[j] = arr[j-1];
 9                 arr[j-1] = tmp;
10                 flag = 1;
11             }
12         }
13         if (flag == 0) break;
14     }
15 }

 

7. 选择排序 (Selection Sort)

 1 void what_sort(int arr[], int n) {
 2     int i, j;
 3     for (i = 0; i < n; i++) {
 4         for (j = i+1; j < n; j++) {
 5             if (arr[i] > arr[j]) {
 6                 int tmp = arr[i];
 7                 arr[i] = arr[j];
 8                 arr[j] = tmp;
 9             }
10         }
11     }
12 }
13 
14 void selection_sort(int arr[], int n) {
15     int i, j;
16     for (i = 0; i < n; i++) {
17         int mini = i, tmp = arr[i];
18         for(j = i+1; j < n; j++) {
19             if (arr[j] < arr[mini]) {
20                 mini = j;
21             }
22         }
23         arr[i] = arr[mini];
24         arr[mini] = tmp;
25     }
26 }

what_sort 其实也是一种选择排序,但是它在性能上比 selection_sort 差一些。

 

8. 逆序对 (Inversions)

在一个序列 A[0 .. n-1] 中,对任意 i, j, 若 i < j 且 A[i] > A[j], 那么 A[i] 和 A[j] 构成一个逆序对。
求序列的逆序对数的最简单的方法就是枚举,时间复杂度为 O(n^2)。

 1 int count_inversions(int arr[], int n) {
 2     int inversions = 0;
 3     int i, j;
 4     for (i = 0; i < n; i++) {
 5         for (j = i+1; j < n; j++) {
 6             if (arr[i] > arr[j]) inversions++;
 7         }
 8     }
 9     return inversions;
10 }

在合并排序的基础上做一些修改,我们能得到一个时间复杂度为O(nlgn)的算法:

 1 void reverse(int arr[], int n) {
 2     int i = 0, j = n-1;
 3     while (i < j) {
 4         int t = arr[i];
 5         arr[i] = arr[j];
 6         arr[j] = t;
 7         i++, j--;
 8     }
 9 }
10 
11 void rotate(int arr[], int n, int k) {
12     reverse(arr, n-k);
13     reverse(arr+n-k, k);
14     reverse(arr, n);
15 }
16 
17 int merge(int arr[], int s, int n) {
18     int inversions = 0;
19     int i = 0, j = s, k = s;
20     while (j < n) {
21         while (i < j && arr[i] <= arr[j]) i++;
22         if (i == j) break;
23         while (j < n && arr[j] < arr[i]) j++;
24         rotate(arr+i, j-i, j-k);
25         inversions += (j-k) * (k-i);
26         i += j-k, k = j;
27     }
28     return inversions;
29 }
30 
31 int count_inversions(int arr[], int n) {
32     int inversions = 0;
33     if (n > 1) {
34         int s = n / 2, t = (n + 1) / 2;
35         inversions += count_inversions(arr, s);
36         inversions += count_inversions(arr+s, t);
37         inversions += merge(arr, s, n);
38     }
39     return inversions;
40 }

* 最后,顺便提一下,本文所介绍的三种排序算法都是稳定的。

 

 

posted @ 2014-06-13 21:32  william-cheung  阅读(214)  评论(0编辑  收藏  举报