java 基本排序

/**
 * 快速排序
 * 分治、遞歸思想
 * 如果要排序數組中下標從 p 到 r 之間的一組數據,我們選擇 p 到 r 之間的任意一個數據作爲 pivot (分區點)。 我們遍歷 p 到 r 之間的數據,將小於 pivot 的放到左邊,將大於 pivot 的放右邊,pivot 放到中間。經過這一步驟之後,數組 p 到 r 之間的數據就被分成了三個部分,前面 p 到 q-1 之間都是小於pivot的,中間是pivot,後面的q+1到r之間是大於pivot的,根據分治、遞歸思想,我們可以用遞歸排序下標從p到q-1之間的數據和下標q+1到r之間的數據,直到區間縮小爲1,就說明所有的都是有序了
 * 最好和平均複雜度爲 O(nlogn),最壞時間複雜度爲O(n²),不穩定的原地排序算法
 *
 * @param data
 */
public static void quickSort(int[] data){
    quickSortInternally(data,0,data.length - 1);
}

private static void quickSortInternally(int[] data,int p,int r){
    if(p>=r) return;
    int midden = getMidden(data,p,r);
    quickSortInternally(data,p,midden - 1);
    quickSortInternally(data,midden + 1,r);
}

private static int getMidden(int[] data,int p,int r){
    int i = p;
    int pivot = data[r];
    for (int j=p;j<r ;j++){
        if(data[j]<pivot){
            int temp = data[i];
            data[i] = data[j];
            data[j] = temp;
            i++;
        }
    }
    int temp = data[i];
    data[i]= data[r];
    data[r] = temp;
    System.out.println("i="+i);
    return i;
}

/**
 * 歸併排序
 * 分治、遞歸思想
 * 要排序一個數組,我們先把數組從中間分成前後兩部分,然後對前後兩部分進行排序,然後將排序好的兩部分合並
 * 最好、最壞、平均時間複雜度都爲 O(nlogn),需要空間複雜度爲O(n),是穩定的非原地算法
 * @param data
 * @param p
 * @param r
 */
public static void mergeSort(int[] data,int p,int r){
    //終止條件
    if(p>=r) return;
    //防止 p和r過大,(p+r)溢出
    int q = p +(r- p)/2;
    //分治遞歸
    mergeSort(data,p,q);
    mergeSort(data,q + 1,r);
    // 將A[p...q]和A[q+1...r]合併爲A[p...r]
    merge(data,p,q,r);
}

private static void merge(int[] data,int p,int q,int r){
    int i= p;
    int j = q +1;
    int k = 0;
    int[] temp = new int[r-p + 1];
    while (i<=q && j<=r){
        if(data[i]<=data[j]){
            temp[k++] = data[i++];
        }else {
            temp[k++] = data[j++];
        }
    }
    // 判斷哪個子數組中有剩餘的數據
    int start = i;
    int end = q;
    if(j<=r){
        start = j;
        end = r;
    }
    // 將剩餘的數據拷貝到臨時數組tmp
    while (start <= end){
        temp[k++]=data[start ++];
    }
    //將臨時變量拷貝回a[p..r]
    for (i=0;i<=r-p;i++){
        data[p+i] = temp[i];
    }
}

/**
 * 冒泡排序,只會操作相鄰的兩個數據。每次冒泡操作都會對相鄰的兩個元素進行比較,看是否滿足大小關係要求,如果不滿足就讓他互換。一次冒泡會讓至少一個元素移動到它應該在的位置,重複n次,就完成了n個數據的排序工作
 * 爲原地穩定算法,時間複雜度爲n²,最好時間複雜度爲n,平均和最壞情況爲n²
 * @param data
 */
public static void bubbleSort(int[] data){
    if(data ==null || data.length <= 1) return;
    int n = data.length;
    for (int i=0;i<n;i++){
        //提前退出標識
        boolean flag =false;
        for(int j=0;j<n-i-1;j++){
            if(data[j]>data[j+1]){
                int temp = data[j];
                data[j]  = data[j+1];
                data[j+1] = temp;
                flag = true;
            }
        }
        if(!flag) break;
    }
}

/**
 * 插入排序
 * 首先我們將數組中數據分爲兩個區間,已排序和未排序區間。初始化時已排序區間只有一個元素,就是數組的第一個元素。插入算法的核心思想是取未排序算法中的元素,在已排序算法中找到合適的插入位置將其插入
 * 原地穩定算法,時間複雜度爲O(n2),但它賦值次數比冒泡的少(插入賦值一次,冒泡3次),所以效率比冒泡的高
 * @param data
 */
public static void insertSort(int[] data){
    if(data == null || data.length <= 1) return;
    for (int i=1;i<data.length;i++){
        int val = data[i];
        int j = i - 1;
        //查找插入的位置
        for(; j>=0 ;j--){
            if(data[j]>val){
                //數據移動
                data[j+1] = data[j];
            }else {
                break;
            }
        }
        //找到位置插入
        data [j + 1] = val;
    }
}

public static void main(String[] args) {
    int[] data ={6,11,3,9,8};
    quickSort(data);
    System.out.println("快排結果爲"+ Arrays.toString(data));
    data =new int[]{6,11,3,9,8};
    mergeSort(data,0,data.length-1);
    System.out.println("歸併排序結果爲"+ Arrays.toString(data));
    data =new int[]{6,11,3,9,8};
    bubbleSort(data);
    System.out.println("冒泡排序結果爲"+ Arrays.toString(data));
    data =new int[]{6,11,3,9,8};
    insertSort(data);
    System.out.println("插入排序結果爲"+ Arrays.toString(data));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章