快速排序-歸併排序-插入排序

快速排序算法

快速排序的思想

![quicksort.jpg](pic/quicksort.jpg)

代碼實現

import java.util.Arrays;

public class QuickSort {
    public static void main(String[] args){

        QuickSort quickSort = new QuickSort();
        int arr[] = {4, 6, 1, 2, 9, 0, 3, 11, 5};
        quickSort.quickSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public void quickSort(int[] arr){
        quickSortSub(arr,0,arr.length - 1);
    }
    public void quickSortSub(int[] arr,int low,int high){
        if(low < high){
            int middle = partition(arr, low, high);
            quickSortSub(arr, low, middle - 1);
            quickSortSub(arr,middle + 1,high);
        }
    }

    public int partition(int[] arr,int low,int high){
        int base = arr[high];
        int i = low - 1;
        for(int j = low; j <= high - 1; j++){
            if(arr[j] <= base){
                i++;
                swap(arr,i,j);
            }

        }
        swap(arr,i+1,high);
        return i + 1;
    }

    public void swap(int[] arr,int i,int j){
        int temp = 0;
        temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}

partition函數的另一種實現方式

實現partition函數有不少種方式,前面介紹的方式是兩個指針low和high都是從頭開始,向同一個方向移動,high指針在low的前面,high指針標記的是比基準數大的,low指針標記的是比基準數小的java

接下來咱們一樣採用兩個指針low和high,只不過這兩個指針是相向運動,當兩個指針相遇的時候就中止算法

圖片描述

public int partition1(int[] arr,int low,int high){
        int base = arr[low];
        int i = low;
        int j = high;
        while (i < j){
            while ( arr[j] > base) j--;
            if(arr[j] < base){
                swap(arr, i, j);
                i++;
            }
            while (arr[i] < base) i++;
            if(arr[i] > base){
                swap(arr,i,j);
                j--;
            }
        }
        return i;
    }

時間複雜度

  • 最好時間複雜度

快速排序算法的時間複雜度關鍵在於拆分的時候是否平衡,若是每次拆分的時候,下標恰好在中間,即q = (p+r)/2數組

那麼性能和歸併排序同樣都是O(nlogn)函數

  • 最壞時間複雜度

若是拆分的時候,恰好拆分的地方另外一部分只有一個元素,那麼性能和插入排序沒有什麼區別,那麼此時拆分須要拆分n次,對於每次拆分都須要調用partition函數找到拆分處的下標,partition的時間複雜度爲θ(n)性能

因此最壞時間複雜度爲:θ(n * n) = θ(n^2)ui

基於隨機抽樣的快速排序算法

時間複雜度

圖片描述

最壞時間複雜度:O(n^2)spa

平均時間複雜度:O(nlogn)(元素互異)指針

插入排序

插入排序的思想

圖片描述

僞代碼

圖片描述

實現

import java.util.Arrays;

public class InsertSort {
    public static void main(String[] args){

        InsertSort insertSort = new InsertSort();
        int[] arr = {3, 1, 2, 6, 5, 4};
        insertSort.insertSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public void insertSort(int[] arr){
        for(int i = 1; i < arr.length; i++){
            int key = arr[i];
            int j = i - 1;
            while (j >= 0 && arr[j] > key){
                arr[j + 1] = arr[j];
                j--;
            }
            arr[j + 1] = key;
        }

    }
}

時間複雜度:O(n^2)code

歸併排序算法

快速排序和歸併排序都藉助了分治的思想,可是他們也有所差異-排序

  • 快速排序只有分的過程,而歸併排序既有分的過程也有合的過程;
  • 快速排序是在分的過程當中經過partition函數找到每一個子數組拆分的下標,直到子數組只有一個元素,這個時候就已經排好序了;而歸併排序先經過平分的方法劃分子數組,最後在合的過程進行排序

圖片描述

思想

圖片描述

實現

import jdk.nashorn.internal.objects.NativeInt16Array;

import java.util.Arrays;

public class MergeSort {

    public static void main(String[] args){

        MergeSort mergeSort = new MergeSort();
        int[] arr = {6, 2, 3, 9, 0, 1, 55};
        mergeSort.mergerSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public void mergerSort(int[] arr){
        mergeSortSub(arr,0,arr.length - 1);
    }
    public void mergeSortSub(int[] arr,int low,int high){
       if(low < high){
           int middle = (int) Math.floor((low + high) >> 1);
           mergeSortSub(arr,low,middle);
           mergeSortSub(arr,middle+1,high);
           merge(arr,low,middle,high);
       }
    }
    public void merge(int[] arr,int low,int middle,int high){
        int len1 = middle - low + 1;
        int len2 = high - middle;
        int[] arr1 = new int[len1 + 1 ];
        int[] arr2 = new int[len2 + 1];
        for(int i = 0; i < len1; i++){
            arr1[i] = arr[low + i];
        }
        for(int i = 0; i < len2; i++){
            arr2[i] = arr[middle + i + 1];
        }
        //防止數組越界
        arr1[len1] = Integer.MAX_VALUE;
        arr2[len2] = Integer.MAX_VALUE;
        int t = 0, s = 0;

        for(int i = low; i <= high; i++){
            if(arr1[t] <= arr2[s]){
                arr[i] = arr1[t];
                t++;
            }else {
                arr[i] = arr2[s];
                s++;
            }

        }

    }
}

時間複雜度

執行拆分的時候須要執行:log2(n)次

圖片描述

有多少次拆分就須要多少次合併,每次合併的時候須要比較的次數:n次,n = high - low + 1

因此總的時間複雜度爲:θ(logn * n) = θ(nlogn)

相關文章
相關標籤/搜索