桶排序的基本思路是遍歷一個待排的數組,把每一個數出現的次數記錄到一個新的數組裏面,那這個新的數組裏的下標就是待排序的數組的值.html
設待排數組是arr,記錄待排數組的桶是bucket讓咱們來理一下思路:java
如下是Java代碼:算法
public static void bucketSort(int [] arr){ int[] bucket=new int[max(arr)+1]; for (int i = 0; i < arr.length; i++) { bucket[arr[i]]++; } int count=0; for (int i=0;i<bucket.length;i++){ for (int j = 1; j <= bucket[i]; j++) { arr[count++]=i; } } }
以上只是一個簡單的桶排序,不能排序負數和小數,但它的時間複雜度也僅僅是T(N)=O(N+M)
;數組
冒泡排序的的思路就是遍歷數組,交換(swap)相鄰兩個元素,使餘下未排序數組部分最大(或最小)的元素浮到最前或最後;
這樣排序一個長度爲N的數組所須要的時間複雜度T(N)=O(N<sup>2</sup>)
app
如下是java代碼:ide
public static void bubbleSort(int [] arr){ for (int i = arr.length; i > 0; i--) { for (int j = 0; j < i-1; j++) { if (arr[j]>arr[j+1]){ swap(arr,j,j+1); } } } }
冒泡排序的缺點很明顯,在所有無序的狀況下,時間複雜度過高了(由於它只能交換相鄰兩個元素);
並且上述的示例有一個須要改進的地方就是:設想一個數組前半部分是有序的,可是若是有序的話檢查一次就夠了(前面在排序後半部分的元素中已經檢查過了),因此咱們能夠設一個布爾型的flag值,有序就直接跳過,這樣能大大縮短代碼運行時間;oop
選擇排序和冒泡排序有點相似,它的基本思路就是把數組當作兩部分:一部分有序,一部分無序;
把後面無序的部分的最小值放到前半部分的最後面(冒泡排序是交換相鄰的元素)ui
如下是java代碼:spa
public static void selectionSort(int[] arr){ for (int i = 0; i < arr.length; i++) { for (int j = i+1; j < arr.length; j++) { if (arr[j]<arr[i]){ swap(arr,j,i); } } } }
選擇排序的時間複雜度也是O(N<sup>2</sup>)
code
插入排序的基本思路是選擇後面沒排序的部分的第一個元素,插入到前半部分有序的合適位置(和選擇排序正好相反);
讓咱們來理一下思路吧:
如下是java代碼:
/** * thought the arr as two part, the front part is ordered and the end part is unordered; * in the loop each time put the fist element of the end part to the appropriate position in the front part; * until the outer loop is over; * @param arr the array wait to sort; */ public static void insertionSort(int[] arr){ for (int i = 0; i < arr.length; i++) { for (int j = 0; j < i; j++) { if (arr[i]<arr[j]){ int tmp=arr[i]; for (int k = i; k > j; k--) { arr[k]=arr[k-1]; } arr[j]=tmp; break; } } } }
因爲有兩層循環,因此它的時間複雜度也是O(N<sup>2</sup>)
,不過和選擇排序不一樣的是它是穩定的排序;
快速排序採用分治法(divide-and-conquer method),利用遞歸(recursion)對數組做拆分處理;
分治法的基本思路就是:大事化小,小事化無;
讓咱們來理一下思路吧:
java代碼以下:
/** * <quote>Quicksort is a divide-and-conquer method for sorting.</quote> * divide the arr to two parts, set the leftest element as the standard position; * find the smaller element than standard position from the right; * find the larger element than standard position from the left; * @param arr the arr wait to sort * @param left left guard * @param right right guard */ public static void quickSort(int[] arr,int left,int right){ if (left>right) return; int i=left,j=right,pos=arr[left]; while(i!=j){ while(i<j&&arr[j]>=pos){ j--; } while(i<j&&arr[i]<=pos){ i++; } if (i<j){ swap(arr,i,j); } } arr[left]=arr[i]; arr[i]=pos; quickSort(arr,left,i-1); quickSort(arr,i+1,right); }
因爲快排是跳躍交換元素位置的(和冒泡排序不一樣),因此它的平均時間複雜度是O(NlogN)
;
沒接觸到遞歸的同窗可能以爲快排有點抽象,能夠參照<啊哈,算法>或<算法第四版>(實際上我也在用這兩本教材),你也能夠看看發明者關於快排的論文;
如下是每種算法的平均時間複雜度:
name | T(N) |
---|---|
bucket sort | O(N+M) |
buble sort | O(N2) |
selection sort | O(N2) |
insertion sort | O(N2) |
quick sort | O(NlogN) |
還有其餘的希爾排序,堆排序,計數排序,基數排序啊有待讀者們去一一探索,這裏就再也不一一贅述了.
原文連接:<算法第四版>最佳實踐