個人面試準備過程--排序算法(更新中)

寫在最前面

導師貪腐出逃美國,兩年未歸,可憐了我。拿了小米和美團的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

快排的優化
  1. 優化選取樞軸,優化沒必要要的交換
    三數取中,即取三個關鍵字先進行排序,將中間數做爲樞軸, 通常是取左端、右端和中間三個數, 也能夠隨機選取。
    修改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);
        }
    }
  2. 優化小數組時的排序方案
    快速排序適用於很是大的數組的解決辦法, 那麼相反的狀況,若是數組很是小,其實快速排序反而不如直接插入排序來得更好(直接插入是簡單排序中性能最好的)。其緣由在於快速排序用到了遞歸操做,在大量數據排序時,這點性能影響相對於它的總體算法優點是能夠忽略的,但若是數組只有幾個記錄須要排序時,這就成了大材小用,所以咱們須要改進一下 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;
        }
    }
  3. 優化遞歸操做
    遞歸對性能是有必定影響的, 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);」。結果相同,但因採用迭代而不是遞歸的方法能夠縮減堆棧深度,從而提升了總體性能。

本節參考 http://blog.csdn.net/scgaligu...

歸併排序

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;
        }
    }

本文參考 http://blog.csdn.net/xsf50717...

相關文章
相關標籤/搜索