通常所謂的基礎排序算法指的是時間複雜度爲O(n^2)的算法。經常使用的有選擇排序、插入排序、冒泡排序等。在這裏,咱們主要來分析前面兩個算法。c++
1. 原理
以下圖所示有8個數據:算法
首先遍歷第二個數字開始的全部數字,找到最小的那個,而後和第一個數字進行比較,若是比他小,就和他進行交換,不然不交換。以下圖所示:數組
以此類推,從第N個數字開始繼續尋找最小的數字,和第N個數字進行交換(N是指循環的次數,第一次和第一個數,第二次和第二個數...),以下圖所示:測試
這樣下去就能夠把整個數組進行排序了。優化
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
1. 原理
插入排序的原理相似於在玩撲克牌時,對牌進行排序的操做。例若有下面8個數據:排序
首先選取第二個元素,讓它和第一個元素進行比較,若是比第一個元素小,就將二者進行調換,以下圖所示:ip
這樣前面兩個數字就排好序了,接着講第三個元素與第二個進行比較,比第二個小就進行交換,交換完了再和第一個進行比較,比第一個小就繼續進行交換,以此類推,以下圖所示:
it
以此類推,後面的數字也是這樣以此和前面的數據進行比較、交換,這樣就能夠把整個數組給拍好了。
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個數字,固定第一個數字不變,,以下圖所示:
接下里分三步進行操做,以下圖所示:
這樣就將前面兩個數排序完成了。接下里的數再進行以下操做:
這樣就將前面三個數排序完成了。以此類推能夠將全部的數排序完成。這裏咱們都是使用賦值操做,因此速度會比以前的交換操做來的快。
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)級別的算法。因此,插入排序常常做爲一個子過程對複雜的排序算法進行優化。