zoukankan      html  css  js  c++  java
  • 《算法导论》(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("
    ");
    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("
    ");
    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 }

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

  • 相关阅读:
    原创:Qt自定义拖放
    看下最近公司的招聘需求
    leveldb阅读心得
    Relationship between the FIX Protocol's OrdID, ClOrdID, OrigClOrdID?
    Wait Functions
    全局变量与单例模式
    Asynchronous I/O
    QuickFix MsgHandler
    第一个Java程序
    (原創) Function Pointer、Delegate和Function Object (C/C++) (template) (.NET) (C#)
  • 原文地址:https://www.cnblogs.com/william-cheung/p/3787590.html
Copyright © 2011-2022 走看看