算法學習與代碼實現2——插入排序

算法學習與代碼實現2——插入排序

算法思路

插入排序其實就是鬥地主抓拍的過程,大神級玩家除外,上學時我們寢室一大神,打牌時手中的牌從來不按套路放,我看的是雲裏霧裏,但人家卻心中有數。我不是大神,我鬥地主只能按順序放牌,右邊小左邊大,而且摸牌的時候必須隨時排序。

插入排序就是個摸牌的過程,每摸到一張牌,就從左邊開始對比,直到找到一張手中已有的牌小於或等於這張新摸到的牌,然後把這張牌插入到該牌的左邊。

算法性能

插入排序是第一個涉及到的排序算法,要列出它的性能,先要知道幾個指標。

穩定性

關於一個排序是否是穩定排序,標準是排序過程中兩個相等的數的相對位置。假設待排序的數組中有連個5,那麼排序後這兩個5的相對位置如果能保證不變,就是穩定排序,否則就是不穩定排序。

時間複雜度

時間複雜度其實就是判斷一個排序所用時間的數量級,一般存在最好時間複雜度,最差時間複雜度和平均時間複雜度。

空間複雜度

就是排序過程中佔用的額外存儲空間。

插入排序的性能

穩定性:穩定排序

時間複雜度:
平均情況:O(n^2),最好情況:O(n),最壞情況:O(n^2)

空間複雜度:
O(1)

僞代碼

INSERTION-SORT(A)
    for j <- 2 to length[A]
        do key <- A[j]
        ▷ Insert A[j] into the sorted sequence A[1..j-1].
        i <- j-1
        while i > 0 and A[i] > key
            do  A[i + 1] <- A[i]
                i <- i - 1
        A[i+1] <- key

C語言實現

在準備實現的過程中發現排序這種代碼還是c/c++實現着有點意義,Python人家已經有了排序了,不需要我們實現,而且想實現貌似也無從下手。

C語言實現插入排序的函數如下:

#include "insertion.h"

void insertion_sort(int * array, int numb){
    int key, i;
    for (int j = 1; j < numb; j++) {
        key = array[j];
        i = j - 1;
        while ( i >= 0 && array[i] > key) {
            array[i + 1] = array[i];
            i--;
        }
        array[i + 1] = key;
    }
}

藉助上一篇介紹的生成隨機數並寫入文件的工具,生成一個一逗號隔開的隨機數文件,用於測試,測試中讀取文件中的隨機數,並將排序後的數寫入另一個文件,測試代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "insertion.h"

int main(int argc, char *argv[])
{   
    if (argc != 3) {
        printf("usage:\n");
        printf("\tsort <filein> <fileout>\n");
        return -1;
    }
    FILE *fin = fopen(argv[1], "r");
    if (NULL == fin) {
        printf("open error\n");
        return -1;
    }
    char sep;
    int numb = 0;
    do {
        sep = fgetc(fin);
        if ( sep == ',')
            numb++; // get the count of the numbers in the input file
    } while (EOF != sep);
    printf("count of numbers in file \"%s\" is %d\n", argv[1], numb);
    fseek(fin, 0, SEEK_SET);
    int * iout = (int*)malloc(sizeof(int) * numb);
    int *p = iout;
    while (!feof(fin)) {
        int a;
        fscanf(fin, "%d,", &a);
        *p++ = a;
    }
    fclose(fin);

    // sort
    insertion_sort(iout, numb);
    FILE * fout = fopen(argv[2], "w");
    for (int i = 0; i < numb; i++) {
        fprintf(fout, "%d,", *(iout + i));
    }
    fclose(fout);
}

小知識,小經驗總結

1. 判斷文件中有多少個以逗號隔開的數

do {
    sep = fgetc(fin);
    if ( sep == ',')
        numb++; // get the count of the numbers in the input file
} while (EOF != sep);

通過fgetc()函數一個個讀入文件中的字符,記錄其中逗號的個數。當讀到EOF時結束。

2. 移動文件指針fseek

fseek接受三個參數,第一個是文件描述符;第二個是移動的偏移量,正數表示正向偏移,複數表示反向偏移;第三參數是偏移的起始點,有三個預定義的值:SEEK_CUR、 SEEK_END 和 SEEK_SET,分別表示當前位置、文件結尾、文件開頭。

3. 將文件中的字符串以數字形式讀出

文件中自然只能保存字符串,想要將其按int形式讀出,可使用fscanf進行格式化讀入,循環使用fscanf,通過feof()函數判斷是否已經讀到了文件結尾。

本文代碼託管於:
https://github.com/haoranzeus/algorithms_study

發佈了51 篇原創文章 · 獲贊 2 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章