面試之排序算法(持續更新)

本文根據個人需要,相對排序算法進行學習。
且主要分爲兩部分:
常用排序算法實現(快速、二分查找、計數排序)
多種算法比較
————————————————————————————————————
1、快速排序
主要思想:選取一個關鍵數據(隔板),依次遍歷數據,如果數據比隔板大,則放到隔板後面,如果比隔板小,則放到隔板前面。這樣一趟排序就可以把隔板元素的最終位置確定下來,然後依次遞歸確定其他元素位置。
快速排序關鍵的地方在於隔板函數partition的實現,它可以確定隔板元素的最終位置並返回最終下標。
這裏有兩種實現方法
第一種:劍指offer中

public int partition(int data[],int start,int end){
    if(data==null||data.length<1||start<0||end>data.length-1)
        return -1;
    //small爲每次遞歸開始的下標前一個位置,這樣只有有滿足小於隔板值纔會移動
    int small=start-1;
    //i<=end也沒用 只會增加一次循環,因爲不滿足data[end]<data[end]
    for(int i=start;i<end;i++){
    //不能等於 只能小於 因爲small代表小於其值的最右下標,否則 直接跨過 出現data[end]左邊值爲等於和小於data[end],多餘的計算比較
    //如果中間有>=隔板元素data[end]的值,則small不會++,除非後面有<data[end]的元素,然後small++,並交換>=和小於data[end]值交換,此時small值仍是最右小於隔板元素的下標。
        if(data[i]<data[end]){
            ++small;
            if(i!=small){
                swap(data,i,small);
            }
        }
    }
    //small的值爲最右邊小於隔板值得下標,所以small+1就是隔板元素的最終下標
    ++small;
    swap(data,small,end);
    return small;
}

第二種:最簡單常見的

public int partition(int data[],int start,int end){
    if(data==null||data.length<1||start<0||end>data.length-1)
        return -1;
    int l=start;
    int h=end;
    int povit=data[start];
    while(l<h){
        while(data[h]>=povit&&l<h)
            h--;
        if(l<h){
            swap(data,l,h);
            l++;
        }
        while(data[l]<=povit&&l<h)
            l++;
            if(l<h){
                swap(data,l,h);
                h--;
            }
    }
    return l;   
}

快速排序

public void quickSort(int data[],int start,int end){
    //遞歸結束條件
    if(start==end)
        return;
    int index=partition(data,start,end);
    if(index>start)
        quickSort(data,start,index-1);
    if(index<end)
        quickSort(data,index+1,end);
}

2、二分查找

public class BinarySearch {
    public static int binarySearch(int data[],int des){
        if(data==null||data.length<1)
            return -1;
        int l=0;
        int h=data.length-1;
        //<=包含等於是可能有這種情況 小標爲3和4 mid=3,但是3<key(4),l++=h 這個時候如果不能等於則會丟失可能找不到
        while(l<=h){
            int mid=(l+h)/2;
            if(data[mid]==des)
                return mid;
            else if(data[mid]>des)
                h=mid-1;
            else
                l=mid+1;
        }
        return -1;
    }

3、計數排序
一般適用於輸入數組值取值範圍一定,比如取值0-k或者年齡小於100等
例題:輸入一個長度爲n的非負整數數組,取值範圍爲0-k,請用線性時間複雜度完成排序

public int [] countingSort(int data[],int k){
    if(data==null||data.length<1||k<0)
        return null;
    int numbers[]=new int[k+1];
    int result[]=new int[data.length];
    for(int i=0;i<data.length;i++){
        numbers[data[i]]++;
    }
    for(int i=1;i<=k;i++){
        numbers[i]=numbers[i]+numbers[i-1];
    }
    for(int i=data.length-1;i>=0;i--){
        result[numbers[data[i]]-1]=data[i];
        numbers[data[i]]--;
    }
    return result;
}

不需要額外存儲空間

    public int [] countSort(int data[],int k){
        if(data==null||data.length<1||k<0)
            return null;
        int numbers[]=new int[k+1];
        for(int i=0;i<data.length;i++){
            numbers[data[i]]++;
        }
        int index=0;
        for(int i=0;i<=k;i++){
            for(int j=0;j<numbers[i];j++){
                data[index]=i;
                index++;
            }
        }
        return data;
    }

各個算法的比較
這裏寫圖片描述
冒泡排序與選擇排序區別:冒泡排序每次選擇剩餘最大的放在後面,比較進行交換,在這過程中可能會發生多次交換,而選擇排序可以選擇剩餘比較小的放在前面,但是過程中發生交換次數比較少,基本是最後找到剩餘最小的放在對應的位置。
插入排序與選擇排序區別:插入排序也是從前面開始有序區,但是前面有序區並非元素最終位置,會根據後面元素大小來調位置,而選擇則是最終位置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章