最近複習《資料結構》,複習到了內部排序,就把書上的演算法用代碼實現了。課本用的是嚴慧敏老師主編的那本。插入排序演算法演算法思想很簡單,就是從第二個元素開始把每個元素逐個插入到前面已排好序的有序表中,漸增的實現排序。下面用一個虛擬碼來理解一下:
InsertSort(A)for m← 2 to length[A] do key ← A[m] n ← m-1 while n>0 and A[n]>key do A[n+1] ← A[n] n ← n-1 A[n+1] ←key
這個演算法的時間複雜度是O(n^2)。時間消耗在了元素間的比較和移動上了,如果能減少元素間的比較或者是元素的移動那麼就能提高了。後面的文章中用介紹用於減少元素間比較次數的折半插入排序;和用於減少元素的移動的2-路插入排序;以及不需要移動元素的表插入排序。
根據上面的虛擬碼很容易寫出原始碼,就像下面的這樣:
//直接插入排序//參數 numbers 是:指向要排序數的數組//宏定義 COUNT 是:數組中元素的個數void DirectInsertSort(int* numbers){int m,n=0;for(m=2;m<COUNT;m++){int key = numbers[m];n=m-1;while( n>0 && numbers[n]>key){numbers[n+1] = numbers[n];n--;}numbers[n+1] = key;}}
如果把儲存數的數組的第一個元素用來當哨兵的話,很容易把函數改成如下的形式:
//直接插入排序//參數 numbers 是:指向要排序數的數組//宏定義 COUNT 是:數組中元素的個數void DirectInsertSort(int* numbers){int i,j=0;for(i=2;i<COUNT;i++){if(numbers[i] < numbers[i-1]){// numbers[0] 當哨兵numbers[0] = numbers[i];for(j=i-1; numbers[0]<numbers[j];j--){numbers[j+1] = numbers[j];}numbers[j+1] = numbers[0];}}}
哨兵元素的好處:
從上面兩段代碼就能看出有了哨兵的好處:每次不必判斷n>0了,也就是說不用檢查數組是否越界了。這在很少數的排序中看不出效果,但當要排列的數很多的時候,
效能就能比較出來了。
下面貼出這次的整個代碼,接下來幾篇會介紹折半插入排序、2-路插入排序和表插入排序:
#include <iostream>using namespace std;#define COUNT 9//輸出排序後的數組void PrintValues(int* numbers){for(int i=1;i<COUNT;i++){cout<<numbers[i]<<" ";}}//直接插入排序//參數 numbers 是:指向要排序數的數組//宏定義 COUNT 是:數組中元素的個數void DirectInsertSort(int* numbers){int m,n=0;for(m=2;m<COUNT;m++){int key = numbers[m];n=m-1;while( n>0 && numbers[n]>key){numbers[n+1] = numbers[n];n--;}numbers[n+1] = key;}/*int i,j=0;for(i=2;i<COUNT;i++){if(numbers[i] < numbers[i-1]){numbers[0] = numbers[i];for(j=i-1; numbers[0]<numbers[j];j--){numbers[j+1] = numbers[j];}numbers[j+1] = numbers[0];}}*/}int main(int argc, char *argv[]){//第一個元素當哨兵位,不用。int values[COUNT] = {0, 49, 38, 65, 97, 76, 13, 27, 49};DirectInsertSort(values);PrintValues(values);return EXIT_SUCCESS;}
結果如: