1. 程式人生 > >演算法導論---演算法分析----插入排序---001

演算法導論---演算法分析----插入排序---001

演算法中有各種排序,然而真正踏踏實實的,認真理解和掌握的,真是不是特多,現在工作,已經是學以致用,但是,演算法基礎還是很重要的,所以最近在看算《演算法導論》這本書,學習之餘,也一步步把各種演算法,羅列一些,最後再做個比較,後面一段時間,會集中精力深入研究下演算法導論。 

1.插入排序

是有一個已經有序的資料序列,要求在這個已經排好的資料序列中插入一個數,但是要求插入後此資料序列仍然有序。插入排序的基本操作就是講一個數據插入到已經排好序的資料中,從而得到一個新的,個數甲乙的有序資料。

演算法適合於少量資料的排列,時間複雜度O(n^2)。

2.內部排序和外部排序

根據排序過程中涉及的儲存器不同,可以將排序方法分為兩大類:一類是內部排序,指的是待排序的機率存放在計算機隨機儲存器中進行的排序過程;另一類的外部排序,指的是排序中要對外儲存器進行訪問的排序過程。

內部排序是排序的基礎,在內部排序中,根據排序過程中所依據的原則可以將它們分為5類:插入排序、交換排序、選擇排序、歸併排序和基數排序;根據排序過程的時間複雜度來分,可以分為三類:簡單排序、先進排序、基數排序。

評價排序演算法優劣的標準主要是兩條:一是演算法的運算量,這主要是通過記錄的比較次數和移動次數來反應;另一個是執行演算法所需要的附加儲存單元的的多少。

3.分類

包括:直接插入排序,二分插入排序(又稱折半插入排序),連結串列插入排序,希爾排序(又稱縮小增量排序)。屬於穩定排序的一種(通俗地講,就是兩個相等的數不會交換位置) 。

4.原理

將n個元素的數列分為已有序和無序兩個部分,如

插入排序過程示例

插入排序過程示例

下所示:

{{a1},{a2,a3,a4,…,an}}

{{a1⑴,a2⑴},{a3⑴,a4⑴ …,an⑴}}

{{a1(n-1),a2(n-1) ,…},{an(n-1)}}

每次處理就是將無序數列的第一個元素與有序數列的元素從後往前逐個進行比較,找出插入位置,將該元素插入到有序數列的合適位置中。

假設在一個無序的陣列中,要將該陣列中的數按插入排序的方法從小到大排序。假設啊a[]={3,5,2,1,4};插入排序的思想就是比大小,滿足條件交換位置,一開始會像氣泡排序一樣,但會比冒泡多一步就是交換後(a[i]=a[i+1]後)原位置(a[i])會繼續和前面的數比較滿足條件交換,直到a[i+1]前面的陣列是有序的。比如在第二次比較後陣列變成a[]={2,3,5,1,4};

5.設計步驟

演算法設計有很多方法。插入排序使用的是增量(incremental)方法;在排好子陣列A[1..j-1]後,將A[j]插入,形成排好序的子陣列A[1..j];

步驟

⒈從有序數列和無序數列{a2,a3,…,an}開始進行排序;

⒉處理第i個元素時(i=2,3,…,n),數列{a1,a2,…,ai-1}是已有序的,而數列{ai,ai+1,…,an}是無序的。用ai與ai-1,a i-2,…,a1進行比較,找出合適的位置將ai插入;

⒊重複第二步,共進行n-i次插入處理,數列全部有序。

兩張圖都是一個意思,第一個是百科上的,第二個是書上的,本來想畫一張來著,後來想著還是直接拍來的實在。

思路

假定這個陣列的序是排好的,然後從頭往後,如果有數比當前外層元素的值大,則將這個數的位置往後挪,直到當前外層元素的值大於或等於它前面的位置為止.這具演算法在排完前k個數之後,可以保證a[1…k]是區域性有序的,保證了插入過程的正確性.


#include <stdio.h>
#define Num 10
int main(int argc, const char * argv[]) {
    int arr[] = {1,12,3,5,7,9,12,16,21,23};
    int count = sizeof(arr)/sizeof(arr[0]);
    for (int i = 0; i <count; i++) {
        int j = i;
        int temp = arr[i];
        while (j > 0 && temp < arr[j-1]) {  //大於0防止越界,寫在&&前面
            arr[j] = arr[j-1];
            j--;
        }
        arr[j] =temp;
    }
    for (int i = 0; i <count; i++) {
        printf("[%2d]:%d\n",i ,arr[i]);
    }
    
    return 0;
}

PS:附:效率分析

穩定

空間複雜度O(1)

時間複雜度O(n2)

最差情況:反序,需要移動n*(n-1)/2個元素

最好情況:正序,不需要移動元素

陣列在已排序或者是“近似排序”時,插入排序效率的最好情況執行時間為O(n);

插入排序最壞情況執行時間和平均情況執行時間都為O(n2)。

通常,插入排序呈現出二次排序演算法中的最佳效能。

對於具有較少元素(如n<=15)的列表來說,二次演算法十分有效。

在列表已被排序時,插入排序是線性演算法O(n)。

在列表“近似排序”時,插入排序仍然是線性演算法。

在列表的許多元素已位於正確的位置上時,就會出現“近似排序”的條件。

通過使用O(nlog2n)效率的演算法(如快速排序)對陣列進行部分排序,

然後再進行選擇排序,某些高階的排序演算法就是這樣實現的。

從上述分析中可以看出,直接插入排序適合記錄數比較少、給定序列基本有序的情況