(PS:原博客戳這裏。原博主寫的太好了,因此直接轉載過來。爲了本身可以學習清楚,我將代碼部分刪掉替換成本身寫的代碼,方便之後查看。)html
十種常見排序算法能夠分爲兩大類:算法
0.3 相關概念數組
冒泡排序是一種簡單的排序算法。它重複地走訪過要排序的數列,一次比較兩個元素,若是它們的順序錯誤就把它們交換過來。走訪數列的工做是重複地進行直到沒有再須要交換,也就是說該數列已經排序完成。這個算法的名字由來是由於越小的元素會經由交換慢慢「浮」到數列的頂端。 數據結構
1.2 動圖演示ide
public static void bubbleSort(int[] array) { for (int i = 0; i < array.length; i++) { for (int j = 0; j < array.length - 1 - i; j++) { if (array[j + 1] < array[j]) { int tmp = array[j + 1]; array[j + 1] = array[j]; array[j] = tmp; } } } }
選擇排序(Selection-sort)是一種簡單直觀的排序算法。它的工做原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,而後,再從剩餘未排序元素中繼續尋找最小(大)元素,而後放到已排序序列的末尾。以此類推,直到全部元素均排序完畢。 函數
n個記錄的直接選擇排序可通過n-1趟直接選擇排序獲得有序結果。具體算法描述以下:性能
public static void selectionSort(int[] array) { for(int i=0;i<array.length-1;i++){ int flag=i; int tmp; for(int j=i+1;j<array.length;j++){ if(array[j]<array[flag]){ flag=j; } } tmp=array[i]; array[i]=array[flag]; array[flag]=tmp; } }
表現最穩定的排序算法之一,由於不管什麼數據進去都是O(n2)的時間複雜度,因此用到它的時候,數據規模越小越好。惟一的好處可能就是不佔用額外的內存空間了吧。理論上講,選擇排序可能也是平時排序通常人想到的最多的排序方法了吧。學習
插入排序(Insertion-Sort)的算法描述是一種簡單直觀的排序算法。它的工做原理是經過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。ui
通常來講,插入排序都採用in-place在數組上實現。具體算法描述以下:spa
public static void insertionSort(int[] array) { for (int i = 1; i < array.length; i++) { int cur = array[i]; for (int j = i - 1; j >= 0; j--) { if (cur < array[j]) { array[j + 1] = array[j]; } else { array[j + 1] = cur; break; } } } }
插入排序在實現上,一般採用in-place排序(即只需用到O(1)的額外空間的排序),於是在從後向前掃描過程當中,須要反覆把已排序元素逐步向後挪位,爲最新元素提供插入空間。
1959年Shell發明,第一個突破O(n2)的排序算法,是簡單插入排序的改進版。它與插入排序的不一樣之處在於,它會優先比較距離較遠的元素。希爾排序又叫縮小增量排序。
先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,具體算法描述:
待寫
希爾排序的核心在於間隔序列的設定。既能夠提早設定好間隔序列,也能夠動態的定義間隔序列。動態定義間隔序列的算法是《算法(第4版)》的合著者Robert Sedgewick提出的。
歸併排序是創建在歸併操做上的一種有效的排序算法。該算法是採用分治法(Divide and Conquer)的一個很是典型的應用。將已有序的子序列合併,獲得徹底有序的序列;即先使每一個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲2-路歸併。
public static void mergeSort(int[] array, int start, int end){ if(start<end){ int mid=(start+end)/2; mergeSort(array,start,mid); mergeSort(array,mid+1,end); merge(array,start,mid,end); } } public static void merge(int[] array, int start, int mid, int end){ int p1=start; int p2=mid+1; int k=start; int[] tmp=new int[array.length]; while (p1<=mid&&p2<=end){ if(array[p1]<array[p2]){ tmp[k++]=array[p1++]; }else { tmp[k++]=array[p2++]; } } while (p1<=mid){ tmp[k++]=array[p1++]; } while (p2<=end){ tmp[k++]=array[p2++]; } for(int i=start;i<=end;i++){ array[i]=tmp[i]; } }
歸併排序是一種穩定的排序方法。和選擇排序同樣,歸併排序的性能不受輸入數據的影響,但表現比選擇排序好的多,由於始終都是O(nlogn)的時間複雜度。代價是須要額外的內存空間。
快速排序的基本思想:經過一趟排序將待排記錄分隔成獨立的兩部分,其中一部分記錄的關鍵字均比另外一部分的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。
快速排序使用分治法來把一個串(list)分爲兩個子串(sub-lists)。具體算法描述以下:
public static void quickSort(int[] array, int low, int high) { int p = low; int q = high; if (low < high) { int tmp = array[low]; while (p < q) { while (p < q && array[q] > tmp) { q--; } if (p < q) { array[p] = array[q]; p++; } while (p < q && array[p] < tmp) { p++; } if (p < q) { array[q] = array[p]; q--; } } array[p] = tmp; quickSort(array, low, p - 1); quickSort(array, p + 1, high); } else { return; } }
堆排序(Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆積是一個近似徹底二叉樹的結構,並同時知足堆積的性質:即子結點的鍵值或索引老是小於(或者大於)它的父節點。
待寫
計數排序不是基於比較的排序算法,其核心在於將輸入的數據值轉化爲鍵存儲在額外開闢的數組空間中。 做爲一種線性時間複雜度的排序,計數排序要求輸入的數據必須是有肯定範圍的整數。
待寫
計數排序是一個穩定的排序算法。當輸入的元素是 n 個 0到 k 之間的整數時,時間複雜度是O(n+k),空間複雜度也是O(n+k),其排序速度快於任何比較排序算法。當k不是很大而且序列比較集中時,計數排序是一個頗有效的排序算法。
桶排序是計數排序的升級版。它利用了函數的映射關係,高效與否的關鍵就在於這個映射函數的肯定。桶排序 (Bucket sort)的工做的原理:假設輸入數據服從均勻分佈,將數據分到有限數量的桶裏,每一個桶再分別排序(有可能再使用別的排序算法或是以遞歸方式繼續使用桶排序進行排)。
待寫
桶排序最好狀況下使用線性時間O(n),桶排序的時間複雜度,取決與對各個桶之間數據進行排序的時間複雜度,由於其它部分的時間複雜度都爲O(n)。很顯然,桶劃分的越小,各個桶之間的數據越少,排序所用的時間也會越少。但相應的空間消耗就會增大。
基數排序是按照低位先排序,而後收集;再按照高位排序,而後再收集;依次類推,直到最高位。有時候有些屬性是有優先級順序的,先按低優先級排序,再按高優先級排序。最後的次序就是高優先級高的在前,高優先級相同的低優先級高的在前。
待寫
基數排序基於分別排序,分別收集,因此是穩定的。但基數排序的性能比桶排序要略差,每一次關鍵字的桶分配都須要O(n)的時間複雜度,並且分配以後獲得新的關鍵字序列又須要O(n)的時間複雜度。假如待排數據能夠分爲d個關鍵字,則基數排序的時間複雜度將是O(d*2n) ,固然d要遠遠小於n,所以基本上仍是線性級別的。
基數排序的空間複雜度爲O(n+k),其中k爲桶的數量。通常來講n>>k,所以額外空間須要大概n個左右。