數據結構與算法之基礎排序算法

簡介

通常所謂的基礎排序算法指的是時間複雜度爲O(n^2)的算法。經常使用的有選擇排序、插入排序、冒泡排序等。在這裏,咱們主要來分析前面兩個算法。c++

選擇排序(Selection Sort)

1. 原理
以下圖所示有8個數據:算法

clipboard.png

首先遍歷第二個數字開始的全部數字,找到最小的那個,而後和第一個數字進行比較,若是比他小,就和他進行交換,不然不交換。以下圖所示:數組

clipboard.png

clipboard.png

以此類推,從第N個數字開始繼續尋找最小的數字,和第N個數字進行交換(N是指循環的次數,第一次和第一個數,第二次和第二個數...),以下圖所示:測試

clipboard.png

這樣下去就能夠把整個數組進行排序了。優化

2. 代碼實現
使用c++對其實現spa

template<typename T>
void selectionSort(T arr[], int n){

    for(int i = 0 ; i < n ; i ++){

        int minIndex = i;
        for( int j = i + 1 ; j < n ; j ++ )
            if( arr[j] < arr[minIndex] )
                minIndex = j;

        swap( arr[i] , arr[minIndex] ); //須要使用頭文件#include <algorithm>
    }
}

從上面的代碼能夠看出,對於任何一個數組,選擇排序排序的兩層循環都要徹底執行完的,所以其效率是很是低下的。code

插入排序(Insortion Sort)

1. 原理
插入排序的原理相似於在玩撲克牌時,對牌進行排序的操做。例若有下面8個數據:排序

clipboard.png

首先選取第二個元素,讓它和第一個元素進行比較,若是比第一個元素小,就將二者進行調換,以下圖所示:ip

clipboard.png

這樣前面兩個數字就排好序了,接着講第三個元素與第二個進行比較,比第二個小就進行交換,交換完了再和第一個進行比較,比第一個小就繼續進行交換,以此類推,以下圖所示:
clipboard.pngit

以此類推,後面的數字也是這樣以此和前面的數據進行比較、交換,這樣就能夠把整個數組給拍好了。

2. 代碼實現

template<typename T>
void insertionSort(T arr[], int n){
    
    for (int i = 1; i < n; i ++){ //注意這裏i的小標是從1開始的,由於第0個數是固定不動的
        //尋找元素arr[i]合適的插入位置
        for (int j = i; j > 0; j --) //交換到最後是第二個數與第二個數進行交換,因此這裏是j>0不是j>=0
            if (arr[j] < arr[j-1])
                swap(arr[j],arr[j-1]);
            else //若是已經比前面的數字小了,就不進行交換
                break;
    }
}

從上面的插入排序的原理和代碼能夠看出,插入排序和選擇排序的最大區別在於:插入排序的第二重循環是能夠提早結束的。所以理論上插入排序比選擇排序應該更快一些。可是通過實際的測試以後,發現上面的插入排序比選擇排序運行的更慢,這是什麼緣由呢?咱們查看插入排序的第二重循環裏面,每進行一次比較以後都要進行一次交換操做,而交換操做的運行速度比選擇排序的賦值操做慢得多,也就是說插入排序速度慢的問題就出在了這裏,接下來咱們就對插入排序進行改進。

插入排序的改進

1. 原理
要將時間效率提升,就要犧牲空間!以下圖所示,仍是8個數字,固定第一個數字不變,,以下圖所示:

clipboard.png

接下里分三步進行操做,以下圖所示:

clipboard.png

這樣就將前面兩個數排序完成了。接下里的數再進行以下操做:

clipboard.png

這樣就將前面三個數排序完成了。以此類推能夠將全部的數排序完成。這裏咱們都是使用賦值操做,因此速度會比以前的交換操做來的快。

2. 程序實現
只須要修改內循環中的代碼便可。代碼以下:

void insertionSort(T arr[], int n){
    
    for (int i = 1; i < n; i ++){
        //第一步,將第i個位置的元素賦值給臨時變量e
        T e = arr[i]; 
        //第二步,將依次比較元素第i個位置以前的數是否比臨時變量中的數要大,要大則日後移動
        int j; // j保存元素e應該插入的位置
        for (j = i; j > 0; j--)
            if (arr[j-1] > e) 
                arr[j] = arr[j-1];
            else 
                break;
        //第三步,將臨時變量中的值放到最後一個比它大的位置處
        arr[j] = e;
    }
}

當一個數組自己就有近乎有序的時候,插入排序的速度將會很是的快!甚至會超過有些O(n*log n)的算法!!
當一個數組自己便是有序時,插入排序會變成一個O(n)級別的算法。因此,插入排序常常做爲一個子過程對複雜的排序算法進行優化。

相關文章
相關標籤/搜索