演算法學習之簡單排序

weixin_33976072發表於2016-04-23

簡單排序

簡單排序有三種, 氣泡排序,選擇排序,插入排序

氣泡排序

氣泡排序是一種易於實現的排序演算法, 以升序為例:

有n個數, 需要比較n-1輪, 每輪比較陣列中相鄰的兩個數, 前者大就交換兩數.

第一輪時, 最大的數就會如冒泡般移向隊尾, 下一輪比較就可以少比較一個數.

//氣泡排序
void bubbleSort(int arr[], int n){
    for (int i = 0; i < n-1 ; i++ ) {
        for (int j = 1; j < n - i; j++) {
            if (arr[j - 1] > arr[j]) {
                swap(&arr[j-1], &arr[j]);
            }
        }
    }
}

因為用的是C語言, 遇到了java中完全遇不到的兩個bug.

第一點是交換值, 必須要傳地址才有卵用, 否則毫無卵用

// 交換函式, 必須傳遞引用才能交換成功
// 傳值只是將實參複製給了形參一份, 在函式內如何改變形參與實參無關
// 傳遞引用, &arr[i], 取地址, a = &arr[i], *a = *(&arr[i]) = arr[i]
// 因此改變的就是實參的值
void swap(int *a, int *b){
    int temp = *a;
    *a = *b;
    *b = temp;
}

另一點是獲取陣列長度.

按照道理, 用運算子sizeof可以計算出陣列的容量(位元組數),在除以單個元素的容量就能得到陣列的長度了.

(sizeof(array) / sizeof(array[0]));

結果我真的是naive. 當我想列印陣列時, 搞了個函式

void printfArray(int arr[]){
    int len = sizeof(arr) / sizeof(arr[0]);
    for (int i = 0; i < len; i++) {
        printf("%d, ", arr[i]);
    }
}

怎麼打都只能打出兩個數字, 百思不得其解啊尼瑪

在C/C++中, 陣列在作為引數傳遞時, 會退化為同型別的指標, 並沒有辦法知道指標所指的記憶體容量,除非在申請記憶體時記住它。

無論陣列長度為多少, 以int陣列為例, sizeof(a)始終等於sizeof(int *), 所以函式中傳遞只能把傳陣列個數傳過去

void printfArray(int arr[], int len){
    for (int i = 0; i < len; i++) {
        printf("%d, ", arr[i]);
    }
}

選擇排序

選擇排序, 以升序為例:

第一輪比較, 從arr[0]開始依次比較, 找出最小的數的下標, 記錄下來, 將arr[0]與最小值交換.

第二輪從arr[1]開始依次比較, 找出最小的數的下標, 記錄下來, 將arr[1]與最小值交換.

...

直到交換完成

void selectSort(int arr[], int n){
    for (int i = 0; i < n; i++) {
        int min = i;
        for (int j = i + 1; j < n; j++) {
            if (arr[j] < arr[min]) {
                min = j;
            }
        }
        swap(&arr[i], &arr[min]);
    }
}

插入排序

插入排序的思路是,將單個數字插入有序集合. 大致思想是, 先將第一個數看做有序區, 後面的數依次插入, 形成新的有序區, 直到排序完成.

以升序為例, 比如這樣一個陣列 {4, 2, 7, 3}

第一輪, 第一個數字4看做有序區, 後面的數字插入. 開始比較2和4,發現2更小,繼續向前查詢,沒有數字,因此將2插入4的位置,4向後移。這時陣列變成了{2, 4, 7, 3}

第二次,遍歷到7,向前比較, 有序

第三次,3和7比較,7更大,3應該插入前面。繼續向前比較,比較到2才找到了合適的位置。將3插入4的位置,4、7向後移動一位。

下面開始擼程式碼

// 直接插入排序
void insertSort(int arr[], int n){
    for (int i = 0; i < n; i++) {
        // 後面的數比前面的數大時, 準備插入
        if (arr[i] > arr[i+1]) {
            // 儲存待插入的數
            int temp = arr[i+1];
            int j;
            // 向前查詢合適的插入位置
            for (j = i; j>=0 && temp < arr[j]; j--) {
                // 逐步後移陣列
                arr[j+1] = arr[j];
            }
            // 交換
            arr[j+1] = temp;
        }
    }
}

相關文章