導師貪腐出逃美國,兩年未歸,可憐了我。拿了小米和美團的offer,要被延期,offer失效,工做從新找。把準備過程紀錄下來,共勉。算法
最初級數組
public void bubbleSort(int[] a){ int len = a.length; for(int i = 0; i < len; i++){ for(int j = 1; j < len; j++){ if(a[j - 1] > a[j]){ int temp = a[j]; a[j] = a[j - 1]; a[j - 1] = temp; } } } }
小優化函數
public void bubbleSort(int[] a){ int len = a.length; for(int i = 0; i < len; i++){ for(int j = 1; j < len - i; j++){ if(a[j - 1] > a[j]){ int temp = a[j]; a[j] = a[j - 1]; a[j - 1] = temp; } } } }
大優化,一次冒泡過程沒有交換,直接退出排序性能
public void bubbleSort(int[] a){ int len = a.length; boolean flag = true; while(flag){ flag = false; for(int j = 0; j < len - 1; j++){ if(a[j] > a[j + 1]){ int temp = a[j]; a[j] = a[j + 1]; a[j + 1] = temp; flag = true; } } } }
快速排序是目前應用最普遍的排序算法之一,它是通常場景中大規模數據排序的首選,它的實際性能要好於歸併排序。一般狀況下,快速排序的時間複雜度爲O(nlogn),但在最壞狀況下它的時間複雜度會退化至O(n^2),不過咱們能夠經過對輸入數組進行「隨機化」(打亂元素的排列順序)來避免最壞狀況的發生。除了實際執行性能好,快速排序的另外一個優點是它可以實現「原地排序」,也就是說它幾乎不須要額外的空間來輔助排序。優化
public static void quickSort(int[] a){ qSort(a, 0, a.length - 1); } private static void qSort(int[] a, int low, int high){ if(low < high){ int pivot = partition(a, low, high); qSort(a, low, pivot - 1); qSort(a, pivot + 1, high); } } private static void partition(int[] a, int low, int high){ int pivotValue = a[low]; while(low < high){ while(low < high && a[high] >= pivotValue){ high--; } a[low] = a[high]; while(low < high && a[low] <= pivotValue){ low++; } a[high] = a[low]; } a[low] = pivotValue; return low; }
穩定性的概念並不複雜,它只表示兩個值相同的元素在排序先後是否有位置變化。若是先後位置變化,則排序算法是不穩定的,不然是穩定的。穩定性的定義符合常理,兩個值相同的元素無需再次交換位置,交換位置是作了一次無用功。
兩個循環在進行元素比較時,分別用了小於和大於操做(也能夠改用小於等於和大於等於,可是對性能沒有影響)。這就意味着若是出現和pivot值相同的元素,它都會被做爲交換對象而移動到pivot的前面或者後面,這就出現了值相同的元素會交換順序的問題,於是是不穩定的。ui
本節參考 http://blog.csdn.net/yutianzu....net
優化選取樞軸,優化沒必要要的交換
三數取中,即取三個關鍵字先進行排序,將中間數做爲樞軸, 通常是取左端、右端和中間三個數, 也能夠隨機選取。
修改partition算法code
private static int partition(int[] a, int low, int high){ choosePivotValue(a, low, high); int pivotValue = a[low]; while(low < high){ while(low < high && a[high] > pivotValue){ high--; } //swap(a,low ,high);交換 //採用替換而不是交換的方式進行操做 a[low] = a[high]; while(low < high && a[low] < pivotValue){ low++; } a[high] = a[low]; } a[low] = pivotValue; return low; } private static void swap(int[] a,int low,int high){ int temp = a[low]; a[low] = a[high]; a[high] = temp; } //使中間值處於a[low]的位置 private static void choosePivotValue(int[] a,int low,int high){ int mid = (low + high) / 2; if(a[low] > a[high]){ // 保證左端較小 swap(a, low, high); } if(a[mid] > a[high]){//保證中間較小 swap(a, mid, high); } if(a[mid] > a[low]){//保證中間較小 swap(a, low, mid); } }
優化小數組時的排序方案
快速排序適用於很是大的數組的解決辦法, 那麼相反的狀況,若是數組很是小,其實快速排序反而不如直接插入排序來得更好(直接插入是簡單排序中性能最好的)。其緣由在於快速排序用到了遞歸操做,在大量數據排序時,這點性能影響相對於它的總體算法優點是能夠忽略的,但若是數組只有幾個記錄須要排序時,這就成了大材小用,所以咱們須要改進一下 qSort函數。對象
public static void qSort(int[] a, int low, int high){ if((high - low) > MAX_LENGTH){ int pivot = partition(a, low, high); qSort(a, low, pivot - 1); qSort(a, pivot + 1, high); }else{ insertSort(a); } } private static void insertSort(int[] a){ for(int i = 1; i < a.length; i++){ int key = a[i]; int j = i - 1; while(j >= 0 && a[j] > key){ a[j + 1] = a[j]; } a[j + 1] = key; } }
優化遞歸操做
遞歸對性能是有必定影響的, qSort 函數在其尾部有兩次遞歸操做。
若是待排序的序列劃分極端不平衡,遞歸深度將趨近與N ,而不是平衡時的 logN,就不單單是速度快慢的問題了,棧的大小是頗有限的,每次遞歸調用都會耗費必定的空間 ,函數的參數越多,每次遞歸耗費的空間也越多。若是能減小遞歸,將會提升性能。咱們對 qSort 實施尾遞歸優化。blog
public static void qSort(int[] a, int low, int high){ if((high - low) > MAX_LENGTH){ while(low < high){ int pivot = partition(a, low, high); qSort(a, low, pivot - 1); low = pivot + 1; } }else{ insertSort(a); } }
當咱們將 if 改爲 while 後,由於第一次遞歸之後,變量low就沒有用處了,因此能夠將pivot+1 賦值給low,再循環後,來一次 partition(arr,low,high)時,其效果等同於「qSort(arr, pivot+1, high);」。結果相同,但因採用迭代而不是遞歸的方法能夠縮減堆棧深度,從而提升了總體性能。
public static void sort(int[] a, int low, int high){ int mid = (low + high) / 2; sort(a, low, mid); sort(a, mid + 1, high); merge(a, low, mid, high); } private static void merge(int[] a, int low, int mid, int high){ int i = low; int j = mid + 1; int k = 0; int[] temp = new int[high - low + 1]; while(i <= mid && j <= high){ if(a[i] < a[j]){ temp[k++] = a[i++]; }else{ temp[k++] = a[j++]; } } while(i <= mid){ temp[k++] = a[i++]; } while(j <= high){ temp[k++] = a[j++]; } for(k = 0; k < temp.length; k++){ a[low + k] = temp[k]; } }
public static void choseSort(int[] a){ for(int i = 0; i < a.length; i++){ int lowIndex = i; for(int j = i; j < a.length; j++){ if(a[j] < a[lowIndex]){ lowIndex = j; } } int temp = a[i]; a[i] = a[lowIndex]; a[lowIndex] = temp; } }
public static void insertSort(int[] a){ for(int i = 1; i < a.length; i++){ int j = i - 1; int key = a[i]; while(j >= 0 && a[j] > key){ a[j + 1] = a[j]; j--; } a[j + 1] = key; } }