【算法與數據結構】三種簡單排序 - 冒泡排序、選擇排序、插入排序

冒泡排序

逐個比較相鄰元素,若是逆序則交換。每一趟都會讓一個元素就位,總共比較 n-1 趟。web

n 個元素,須要進行 n - 1 輪冒泡,每次冒泡都會有一個元素就位,因此每輪冒泡的循環次數都會減一。時間複雜度爲:
1 + 2 + … + n-1 = n(n-1)/2 = O(n^2)svg

初始值:		5 4 3 2 1 
首輪冒泡:	4 3 2 1 5  最後一個元素就位
第二輪:		3 2 1 4 5  倒數第二個元素就位
...

基礎版冒泡排序

// 冒泡排序,每輪都會排好一個元素
void bubbleSort(int arr[], int count) {
    int i, j;
    // n 個元素,須要比較 n-1 輪
    for (i = count - 1; i > 0; i--) {
        // 每輪比較,只需在剩餘的 j 個元素中,從頭開始比較 j-1 次
        for (j = 1; j <= i; j++) {
            if (arr[j-1] > arr[j]) {
                swap(arr, j - 1, j);
            }
        }
    }
}

提早結束的冒泡排序

上面的冒泡排序,即便剩餘元素都已經有序,內層 for 循環中沒有發生元素交換,也會繼續執行下去。能夠設置一個值,在剩餘元素都已經就位時提早結束循環:spa

void bubbleSort(int arr[], int count) {
    int i, j, sorted;
    // n 個元素,須要比較 n-1 輪
    for (i = count - 1; i > 0; i--) {
    	sorted = 1;
        // 每輪比較,只需在剩餘的 j 個元素中,從頭開始比較 j-1 次
        for (j = 1; j <= i; j++) {
            if (arr[j-1] > arr[j]) {
                swap(arr, j - 1, j);
                sorted = 0;
            }
        }
        if (sorted == 1) {
			break;
		}
    }
}

標記有序區間的冒泡排序

對於 5 4 3 2 1 9 6 7 8 這樣的數據,第一輪排序以後,最後的部分元素都會就位,而不是僅僅就位一個元素。若是每次都標記有序的區間,也能夠改善冒泡排序的效率:code

void bubbleSort(int arr[], int count) {
	int i, j;
	int last = count - 1;
	for (i = count - 1; i > 0; i--) {
		i = last;
		for (j = 1; j <= i; j++) {
			if (arr[j-1] > arr[j]) {
				swap(arr, j-1, j);
				last = j;
			}
		}
	}
}

選擇排序

冒泡排序每次相鄰元素的比較,均可能會發生元素的交換。若是在一輪掃描中,只記錄最大元素的位置,掃描結束後再判斷是否交換,能夠略微改善效率。xml

選擇排序,就是冒泡排序的簡單改進版,每輪掃描都會選擇一個最大元素,若是這個最大元素未就位,則交換。排序

代碼:token

// 選擇排序,每輪的比較次數跟冒泡同樣,但交換次數最多一次
void selectionSort(int arr[], int count) {
    int i, j, key;
    for (i = count-1; i > 0; i--) {
        key = 0;
        for (j = 1; j <= i; j++) {
            if (arr[j] > arr[key]) {
                key = j;
            }
        }
        if (i != key) {
            swap(arr, i, key);
        }
    }
}

插入排序

玩撲克牌的時候,咱們會把手裏的牌排好次序。每次摸一張牌,都會插入到合適的位置。插入排序,就是這個意思。string

首先咱們把待排序的元素的第一個元素看做有序集合中僅有的元素,而後把第二個元素插入到這個集合的合適位置,而後是第三個,以此類推。it

代碼執行時,仍然是逐個相鄰元素進行比較。每次發現逆序對,就開始執行插入操做,設逆序對前一個元素是 x,後一個元素是 y:io

  1. 用臨時變量 tmp 保存 y 的值。
  2. 比較 y 和 x,若是逆序,則把 x 的值放入 y 的位置
  3. 若是 x-1 未越界,則比較 x 和 x-1,若是逆序,則把 x-1 的值放入 x 的位置,而後把 x-1 看作 x
  4. 重複執行 3,直到越界或非逆序對。
  5. 把 tmp 的值賦給 x

代碼:

// 插入排序,只掃描一輪,只要有逆序對,就將逆序對的後者與以前的元素
// 逐個比較,直到不逆序或越界。將這些元素逐個後移一位,而後插入這個元素
void insertSort(int arr[], int count) {
    int i, j, tmp;
    for (i = 1; i < count; i++) {
        if (arr[i-1] > arr[i]) {
            tmp = arr[i];
            j = i - 1;
            while(j >= 0 && arr[j] > tmp) {
                arr[j+1] = arr[j];
                j--;
            }
            arr[j+1] = tmp;
        }
    }
}

三種排序的完整代碼示例

#include <stdio.h>

void swap(int arr[], int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
// 冒泡排序,每輪都會排好一個元素
void bubbleSort(int arr[], int count) {
    int i, j;
    // n 個元素,須要比較 n-1 輪
    for (i = count - 1; i > 0; i--) {
        // 每輪比較,只需在剩餘的 j 個元素中,從頭開始比較 j-1 次
        for (j = 1; j <= i; j++) {
            if (arr[j-1] > arr[j]) {
                swap(arr, j - 1, j);
            }
        }
    }
}
// 選擇排序,每輪的比較次數跟冒泡同樣,但交換次數最多一次
void selectionSort(int arr[], int count) {
    int i, j, key;
    for (i = count-1; i > 0; i--) {
        key = 0;
        for (j = 1; j <= i; j++) {
            if (arr[j] > arr[key]) {
                key = j;
            }
        }
        if (i != key) {
            swap(arr, i, key);
        }
    }
}
// 插入排序,只掃描一輪,只要有逆序對,就將逆序對的後者與以前的元素
// 逐個比較,直到不逆序或越界。將這些元素逐個後移一位,而後插入這個元素
void insertSort(int arr[], int count) {
    int i, j, tmp;
    for (i = 1; i < count; i++) {
        if (arr[i-1] > arr[i]) {
            tmp = arr[i];
            j = i - 1;
            while(j >= 0 && arr[j] > tmp) {
                arr[j+1] = arr[j];
                j--;
            }
            arr[j+1] = tmp;
        }
    }
}
int main(void) {
    int arr[10] = {2, 8, 1, 5, 3, 0, 4, 9, 7, 6};
    int count = 10;
    int i;
    
    printf("raw:\t");
    for (i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }
    
    // printf("\nbubble:\t");
    // bubbleSort(arr, count);
    // for (i = 0; i < 10; i++) {
    // printf("%d ", arr[i]);
    // }

    // printf("\nselect:\t");
    // selectionSort(arr, count);
    // for (i = 0; i < 10; i++) {
    // printf("%d ", arr[i]);
    // }
    
    printf("\ninsert:\t");
    insertSort(arr, count);
    for (i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }

    return 0;
}
相關文章
相關標籤/搜索