插入排序的基本思想是:每一趟將一個待排序的記錄,按器關鍵字的大小插入到已經排好序的一組記錄的適當位置上,直到全部待排序記錄所有插入爲止。java
例如,打撲克牌在抓牌的時要保證抓過的牌有序排列則每抓一張牌,就插入到合適的位置,直到抓完牌爲止,便可獲得一個有序序列。算法
能夠選擇不一樣的方法在已排好序的記錄中尋找插入位置。根據查找方法的不一樣,有多種插入排序方法,這裏主要介紹直接插入排序。數組
直接插入排序(Straight Insertion Sort)是一種最簡單的排序方法,其基本操做是將一條記錄插入到已排好序的有序表中,從而獲得一個新的、記錄數量增1的有序表動畫
1)設待排序的記錄放在數組中r[1...n]中,r[1]是一個有序序列。ui
2)循環n-1次,每次使用順序查找法,查找r[i](i=2,...n)在已排好序的序列r[1...i-1]中的插入位置,而後將r[i]插入表長爲i-1的有序序列r[1...i-1],直接將r[n]插入表長爲n-1的有序序列r[1...n-1],最後獲得一個表長爲n的有序序列spa
package com.hxy.sort; import java.util.Arrays; public class InsertSort { public static void main(String[] args) { int[] arr ={49,38,65,97,76,13,27,49}; System.out.println("排序以前的數組"); System.out.println(Arrays.toString(arr)); insertSort(arr); System.out.println("排序以後的數組"); System.out.println(Arrays.toString(arr)); } public static void insertSort(int[] arr){ for (int i = 1; i<arr.length;i++){ if(arr[i]<arr[i-1]){//若第i個元素小於第i-1個元素,移動有序序列, 若是大於的話則直接插入 int temp = arr[i];//存儲待插入的記錄 arr[i] = arr[i-1]; int j = i-1; for(;j>=0&&temp<arr[j];j--){//判斷條件 arr[j+1] = arr[j]; } arr[j+1] = temp;// 將待插入的元素插到指定位置 } } } }
結果以下圖所示指針
對於整個排序過程需執行n-1趟,在最好的狀況下(正序:待排序序列中記錄按關鍵字非遞減有序排列),總的移動比較次數達到最小值n-1,記錄不需移動;最壞狀況下(即待排序表爲逆序),總的關鍵字比較次數爲(n+2)(n-1)/2≈/2,記錄移動次數爲(n+4)(n-1)/2≈/2。若待排序序列中出現各類可能排列的機率相同,則可取上述最好狀況和最壞狀況的平均狀況。在平均狀況下,直接插入排序關鍵字的比較次數和記錄移動次數均約爲/4。由此,直接插入排序的時間複雜度爲O()code
直接插入排序只須要一個記錄的輔助空間temp,因此空間複雜度爲O(1)。blog
(1)穩定排序排序
(2)算法簡單,且容易實現
(3)也適用於鏈式存儲結構,只是在單鏈表上無需移動記錄,只需修改相應的指針。
(4)更適合初始記錄基本有序(正序)的狀況,當初始記錄無序,n較大時,此算法的時間複雜度較高,不宜採用
快速排序(Quick Sort)是由冒泡排序改進而得的。在冒泡排序過程當中,只對相鄰的兩個記錄進行比較,所以每次交換兩個相鄰的記錄時只能消除一個逆序。若是能經過兩個(不相鄰)記錄的一次交換,消除多個逆序,則會大大加快排序的速度。快速排序方法中的一次交換可能消除多個逆序。
在待排序的n個記錄中任取一個記錄(一般取第一個記錄)做爲樞軸(或支點),設其關鍵字爲pivotkey。通過一趟排序後,把全部關鍵字小於pivotkey的記錄交換到前面,把全部關鍵字大於pivotkey的記錄交換到後面,結果將待排序記錄分紅兩個子表,最後將樞軸放置在分界處的位置。而後,分別對左、右子表重複上述過程,直至每個子表只有一個記錄時,排序完成。
其中,一趟快速排序的具體步驟以下。
1)選擇待排序表中的第一個記錄做爲樞軸,將樞軸記錄暫存在r[0]的位置上。附設兩個指針low和high,初始時分別指向表的下界和上界(第一趟時,low=1;high=L.length)。
2)從表的最右側位置依次向左搜索,找到第一個關鍵字小於樞軸關鍵字pivotkey的記錄,將其移到low處。具體操做是當low<high時,若high所指記錄的關鍵字大於等於pivotkey,則向左移動指針high(執行操做high- -);不然將high所指記錄與樞軸記錄錄交換。
3)而後再從表的最左側位置,依次向右搜索找到第一個關鍵字大於pivotkey的記錄和樞軸記錄交換。具體操做是:當low<high時,若low所指記錄記錄關鍵字小於等於pivotkey,則向右移動指針low(執行操做low++);不然將low所指記錄與樞軸記錄交換。
4)重複步驟2)和3),直至low與high相等爲止。此時low或high的位置即爲樞軸在此趟排序中的最終位置,原表被分紅兩個子表。
在上述過程當中,記錄的交換都是與樞軸之間發生,每次交換都要移動3次記錄,能夠先將樞軸記錄暫存在r[0]的位置上,排序過程當中只要移動與樞軸交換的記錄,即只作r[low]或r[high]的單向移動,直至一趟排序結束後再將樞軸記錄移至正確位置上
package com.hxy.sort;
import java.util.Arrays;
public class QuickSort {
public static void main(String[] args) {
int[] arr ={8,5,7,6,9,5,4,2,10};
System.out.println("排序以前的順序");
System.out.println(Arrays.toString(arr));
//int [] arr = {4,6};
//int[] arr = {1,2,3,4,5,6,7,7,7,9};
quickSort(arr,0,arr.length-1);
System.out.println("排序以後的順序");
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr , int leftBound, int rightBound){
if(leftBound>=rightBound){
return;
}
int mid = partition(arr, leftBound, rightBound);
quickSort(arr,leftBound,mid-1);
quickSort(arr,mid+1,rightBound);
}
public static int partition(int[] arr,int leftBound,int rightBound){
int pivot = arr[rightBound];
int left = leftBound ;
int right = rightBound-1;
while (left<right){
while (arr[left]<=pivot && left<=right)left++;
while (arr[right]>pivot && left<right)right--;
if(left<right) {
swap(arr, left, right);
}
}
if(arr[left]>pivot)
swap(arr,left,rightBound);
return left;
}
static void swap(int[] arr, int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j]= temp;
}
}
結果以下圖所示
從快速排序算法的遞歸樹可知,快速排序的趟數取決於遞歸樹的深度。
最好狀況下:每一趟排序後都能將記錄序列均勻地分割成兩個長度大體相等的子表,相似折半查找。在n個元素的序列中,對樞軸定位所需時間爲O(n).若設T(n)是對n個元素的序列進行排序所需的時間,並且每次對樞軸正肯定位後,正好把序列劃分爲長度相等的兩個子表,此時,設Cn是一個常數,表示n個元素進行一趟快速排序的時間,則總排序的時間爲
T(n)=Cn+2T(n/2)
≤n+2T(n/2)
≤n+2(n/2+2T(n/4))=2n+4T(n/4)
≤2n+4(n/4+2T(n/8))=3n+8T(n/8)
……
≤kn+2kT(n/2k)
∵k=n
∴T(n) ≤nn+nT(1)≈O(nn)
最壞狀況下:在待排序序列已經排好序的狀況下,其遞歸樹成爲單支樹,每次劃分只獲得一個比上一次少一個記錄的子序列。這樣必須通過n-1趟才能將全部記錄定位,並且第i趟須要通過n-i次比較。這樣,總的關鍵字比較次數爲n(n-1)/2≈n2/2
這種狀況下,快速排序的速度已經退化到簡單排序的水平。樞軸記錄的合理選擇可避免這種最壞狀況的出現,如利用「三者取中」的規則:比較當前表中第一個記錄,最後一個記錄和中間一個記錄的關鍵字,取關鍵字居中的記錄做爲樞軸記錄,事先調換到第一個記錄的位置。
理論上能夠證實,平均狀況下,快速排序的時間複雜度爲O(nn)。
快速排序是遞歸的,執行時須要一個棧來存放相應的數據。最大遞歸調用次數與遞歸輸的深度一致,因此最好的狀況下的空間複雜度爲O 最壞狀況下爲O(n)
1)記錄非順次的移動致使排序方法是不穩定的。
2)排序過程當中須要定位表的下界和上界,因此適合用於順序結構,很難用於鏈式結構。
3)當n較大時,在平均狀況下快速排序是全部內部排序方法中速度最快的一種,因此其適合初始記錄無序、n較大時的狀況。