zoukankan      html  css  js  c++  java
  • 常见排序算法导读(4)[直接插入排序]

    上一节介绍了简单选择排序,这一节将介绍直接插入排序(Straight Insertion Sort)。 会玩扑克牌的同志应该很容易理解插入排序,通常整理扑克牌的方法就是一张一张的来,将每一张扑克牌插入到其他已经有序的扑克牌中的适当位置。在计算机实现中,为了给要插入的元素腾出空间,我们需要将其余所有元素在插入之前都向右移一个位置。这种方法就叫做插入排序(Insertion Sort)。 与选择排序一样,当前索引左边的所有元素都是有序的,但它们的最终位置还不确定,为了给更小的元素腾出空间,它们可能会被移动。但是当索引到达数组的右端时,排序就完成了。

    直接插入排序的思想

    当插入第i(>=1)个对象时,前面的V[0], V[1], ..., V[i-1]已经排好序。这时候, 用V[i]的关键字与V[0], V[1], ..., V[i-1]的关键码顺序进行比较,找到插入位置后将V[i]插入,原来位置上的对象向后顺移。

    典型的直接插入排序的过程看起来是这样子滴,【图片来源: https://en.wikipedia.org/wiki/Insertion_sort】

     o 直接插入排序(Straight Insertion Sort)的C代码实现 : 函数sisort()

     1 static void insert(int a[], int m, int n);
     2 
     3 /*
     4  * Straight Insertion Sort (sisort in short)
     5  */
     6 void sisort(int a[], size_t n)
     7 {
     8     for (int i = 1; i < n; i++) {     // a[i .. n-1] is not sorted
     9         for (int j = 0; j < i; j++) { // a[0 .. i-1] is sorted
    10             if (a[i] < a[j]) {        // walk a[0 .. i-1], if a[i] < a[j]
    11                 insert(a, j, i);      // insert a[i] before a[j]
    12                 break;
    13             }
    14         }
    15     }
    16 }
    17 
    18 /*
    19  * Insert a[n] before a[m]
    20  *                                                .-----------.
    21  *                                                |           |
    22  * o Input : a[m-1], a[m], a[m+1], ..., a[n-1], a[n], a[n+1]  |
    23  *                                                         |
    24  * o Output: a[m-1], a[n], a[m], a[m+1], ..., a[n-1], a[n+1]  |
    25  *                       \____________________________________/
    26  */
    27 static void insert(int a[], int m, int n)
    28 {
    29     int t = a[n];
    30     for (int i = n; i > m; i--)
    31         a[i] = a[i-1];
    32     a[m] = t;
    33 }

    接下来,给出一个完整的sisort.c并编译后测试, 以便形象化地理解直接插入排序的全过程。

    o sisort.c // 将sisort()做稍稍增强以打印详细的排序过程。 注意:下面的程序中某些代码行风格很不好是故意的,因为只是为了帮助打印排序过程故一切从简。

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 typedef struct obs_s {
     5         unsigned int loop;
     6         unsigned int inst;
     7         unsigned int move;
     8 } obs_t;
     9 
    10 obs_t g_obs = { .loop = 0, .inst = 0, .move = 0 };
    11 
    12 static void insert(int a[], int m, int n);
    13 static void show(int a[], size_t n);
    14 
    15 void sisort(int a[], size_t n)
    16 {
    17         for (int i = 1; i < n; i++) {
    18                                 printf("
    #%d:		", i);  show(a, n);
    19                 for (int j = 0; j < i; j++) {           g_obs.loop++;
    20                         if (a[i] < a[j]) {              g_obs.inst++;
    21                                 printf("	<-- insert a[%d] before a[%d]", i, j);
    22                                 insert(a, j, i);
    23                                 break;
    24                         }
    25                 }
    26         }
    27 }
    28 
    29 static void insert(int a[], int m, int n)
    30 {
    31         int t = a[n];
    32         for (int i = n; i > m; i--) {                   g_obs.move++;
    33                 a[i] = a[i-1];
    34         }
    35         a[m] = t;
    36 }
    37 
    38 static void show(int a[], size_t n)
    39 {
    40         for (int i = 0; i < n; i++)
    41                 printf("%c ", a[i]);
    42 }
    43 
    44 int main(int argc, char *argv[])
    45 {
    46         if (argc < 2) {
    47                 fprintf(stderr, "Usage %s <C1> [C2] ...
    ", argv[0]);
    48                 return -1;
    49         }
    50 
    51         argc--;
    52         argv++;
    53 
    54         size_t n = argc;
    55         int *a = (int *)malloc(sizeof(int) * argc);
    56         if (a == NULL) {
    57                 fprintf(stderr, "failed to malloc()
    ");
    58                 return -1;
    59         }
    60 
    61         for (int i = 0; i < n; i++)
    62                *(a+i) = argv[i][0];
    63 
    64         printf("               	0 1 2 3 4 5 6 7 8 9 10
    ");
    65         printf("Before sorting: "); show(a, n);
    66         sisort(a, n);                           printf("
    ");
    67         printf("After  sorting: "); show(a, n); printf("
    ");
    68         printf("
    ");
    69         printf("Total loop      times : %2d
    ", g_obs.loop);
    70         printf("Total insertion times : %2d
    ", g_obs.inst);
    71         printf("Total move      times : %2d
    ", g_obs.move);
    72 
    73         free(a); a = NULL;
    74 
    75         return 0;
    76 }

    o 编译并测试

    $ gcc -g -Wall -m32 -std=c99 -o sisort sisort.c
    
    $ ./sisort      0 1 2 3 4 5 6 7 8 9 a           #[1]
                    0 1 2 3 4 5 6 7 8 9 10
    Before sorting: 0 1 2 3 4 5 6 7 8 9 a
    #1:             0 1 2 3 4 5 6 7 8 9 a
    #2:             0 1 2 3 4 5 6 7 8 9 a
    #3:             0 1 2 3 4 5 6 7 8 9 a
    #4:             0 1 2 3 4 5 6 7 8 9 a
    #5:             0 1 2 3 4 5 6 7 8 9 a
    #6:             0 1 2 3 4 5 6 7 8 9 a
    #7:             0 1 2 3 4 5 6 7 8 9 a
    #8:             0 1 2 3 4 5 6 7 8 9 a
    #9:             0 1 2 3 4 5 6 7 8 9 a
    #10:            0 1 2 3 4 5 6 7 8 9 a
    After  sorting: 0 1 2 3 4 5 6 7 8 9 a
    
    Total loop      times : 55
    Total insertion times :  0
    Total move      times :  0
    
    $ ./sisort      a 9 8 7 6 5 4 3 2 1 0           #[2]
                    0 1 2 3 4 5 6 7 8 9 10
    Before sorting: a 9 8 7 6 5 4 3 2 1 0
    #1:             a 9 8 7 6 5 4 3 2 1 0   <-- insert a[1] before a[0]
    #2:             9 a 8 7 6 5 4 3 2 1 0   <-- insert a[2] before a[0]
    #3:             8 9 a 7 6 5 4 3 2 1 0   <-- insert a[3] before a[0]
    #4:             7 8 9 a 6 5 4 3 2 1 0   <-- insert a[4] before a[0]
    #5:             6 7 8 9 a 5 4 3 2 1 0   <-- insert a[5] before a[0]
    #6:             5 6 7 8 9 a 4 3 2 1 0   <-- insert a[6] before a[0]
    #7:             4 5 6 7 8 9 a 3 2 1 0   <-- insert a[7] before a[0]
    #8:             3 4 5 6 7 8 9 a 2 1 0   <-- insert a[8] before a[0]
    #9:             2 3 4 5 6 7 8 9 a 1 0   <-- insert a[9] before a[0]
    #10:            1 2 3 4 5 6 7 8 9 a 0   <-- insert a[10] before a[0]
    After  sorting: 0 1 2 3 4 5 6 7 8 9 a
    
    Total loop      times : 10
    Total insertion times : 10
    Total move      times : 55
    
    $ ./sisort      S O R T E X A M P L E           #[3]
                    0 1 2 3 4 5 6 7 8 9 10
    Before sorting: S O R T E X A M P L E
    #1:             S O R T E X A M P L E   <-- insert a[1] before a[0]
    #2:             O S R T E X A M P L E   <-- insert a[2] before a[1]
    #3:             O R S T E X A M P L E
    #4:             O R S T E X A M P L E   <-- insert a[4] before a[0]
    #5:             E O R S T X A M P L E
    #6:             E O R S T X A M P L E   <-- insert a[6] before a[0]
    #7:             A E O R S T X M P L E   <-- insert a[7] before a[2]
    #8:             A E M O R S T X P L E   <-- insert a[8] before a[4]
    #9:             A E M O P R S T X L E   <-- insert a[9] before a[2]
    #10:            A E L M O P R S T X E   <-- insert a[10] before a[2]
    After  sorting: A E E L M O P R S T X
    
    Total loop      times : 27
    Total insertion times :  8
    Total move      times : 36

    以上排序过程(#[3])截图如下(截图来源: Algorithms Fourth Edition P251)

    小结: 直接插入排序算法是稳定的算法,其时间复杂度和空间复杂度是:

    Worst-case performance      О(n**2) comparisons, swaps
    Best-case performance       O(n)    comparisons, O(1) swaps
    Average performance         О(n**2) comparisons, swaps
    Worst-case space complexity О(n) total, O(1) auxiliary

    到此为止,我们已经完全弄明白了直接插入排序的原理。其核心就是:在已排好序的i条记录中插入一条新的记录,得到有序的i+1条记录。 下一节,我们将介绍可谓家喻户晓妇孺皆知的一种排序算法,那就是冒泡排序。

  • 相关阅读:
    微信小程序之项目的创建
    Java中的线程--多线程面试题
    Java中的线程--并发库中的集合
    Java中的线程--线程中的工具
    Java中的线程--Lock和Condition实现线程同步通信
    Linux指定用户运行程序
    CPU、内存、磁盘三者的关系
    shell从字符串中提取子串(正则表达式)
    ssh登录失败的常见问题分析
    正则表达式匹配不含有某字符串的行
  • 原文地址:https://www.cnblogs.com/idorax/p/6537424.html
Copyright © 2011-2022 走看看