算法從小白到大神之時間複雜度&幾種排序算法探究

認識時間複雜度

常數時間的操做:一個操做若是和數據量沒有關係,每次都是 固定時間內完成的操做,叫作常數操做。
時間複雜度爲一個算法流程中,常數操做數量的指標。經常使用O (讀做big O)來表示。具體來講,在常數操做數量的表達式中, 只要高階項,不要低階項,也不要高階項的係數,剩下的部分 若是記爲f(N),那麼時間複雜度爲O(f(N))。
評價一個算法流程的好壞,先看時間複雜度的指標,而後再分 析不一樣數據樣本下的實際運行時間,也就是常數項時間。
html

例子一

冒泡排序細節的講解與複雜度分析
時間複雜度O(N^2),額外空間複雜度O(1)
算法

/**
 * 冒泡排序:時間複雜度O(N^2)
 * 測試數組:  int[] arr={2,4,63,6,9};
 * 排序邏輯:
 *  一、先從數組0-arr.length-1遍歷,比較[0-1,1-2,2-3...arr.length-2-arr.length-1]大的放後面,
 *  最後遍歷數組,獲得最後的必定是最大的元素
 *  二、再從數組0-arr.length-2遍歷,比較[0-1,1-2,2-3...arr.length-3-arr.length-2]大的放後面。
 *  三、重複以上邏輯
 *  排序過程:
 *   一、[2,4,|63,6,9],[2,4,63,|6,9],[2,4,6,63,|9],[2,4,6,9,63]
 *   二、[2,4,|6,9,63],[2,4,6,|9,63],[2,4,6,9,|63]
 *   三、[2,4,|6,9,63],[2,4,6,|9,63]
 *   四、[2,4,|6,9,63]
 */
public class BubbleSort {

    public static void sort(int[] arr){
        if (arr==null ||  arr.length<2){
            return;
        }
        for (int end = arr.length-1; end>0; end--) {
            for (int i = 0; i < end; i++) {
                if (arr[i]>arr[i+1]){
                    swap(arr,i,i+1);
                }
            }
        }
    }
    //交換
    private static void swap(int[] arr, int i, int j) {
        arr[i]=arr[i]^arr[j];
        arr[j]=arr[i]^arr[j];
        arr[i]=arr[i]^arr[j];
    }

    //for test
    public static void main(String[] args) {
        int[] arr={2,4,63,6,9};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

例子二

選擇排序的細節講解與複雜度分析
時間複雜度O(N^2),額外空間複雜度O(1)
數組

/**
 * 選擇排序:時間複雜度:O(N^2)
 * 測試數組:int[]arr={2,3,43,4,5,67,84,3,22,35,64};
 * 排序邏輯:
 *  一、先遍歷數組(0-arr.length-1)找最小的那個元素下標:minIndex和i=0位置元素進行交換
 *  二、再遍歷數組(1-arr.length-1)找最小的那個元素下標:minIndex和index=1位置元素進行交換
 *  三、重複步驟。。。。
 *  四、最後遍歷完了全部元素,最後數組按照從小到大的順序排列起來了。
 *  排序過程:
 *  一、[2,|3,43,4,5,67,84,3,22,35,64]
 *  二、[2,3,|43,4,5,67,84,3,22,35,64]
 *  三、[2,3,3,|43,4,5,67,84,22,35,64]
 *  四、[2,3,3,4,|43,5,67,84,22,35,64]
 *  五、[2,3,3,4,5,|43,67,84,22,35,64]
 *  六、[2,3,3,4,5,22,|67,84,43,35,64]
 *  七、[2,3,3,4,5,22,35,|84,43,67,64]
 *  八、[2,3,3,4,5,22,35,43,|84,67,64]
 *  九、[2,3,3,4,5,22,35,43,64,|67,84]
 *  十、[2,3,3,4,5,22,35,43,64,67,|84]
 */
public class SelectionSort {
    public static void selectionSort(int[]arr){
      if (arr==null || arr.length<2){
          return;
      }
        for (int i = 0; i < arr.length; i++) {
            int minIndex=i;
            for (int j = i+1; j < arr.length; j++) {
                minIndex=arr[j]<arr[minIndex]?j:minIndex;
            }
            if (minIndex!=i){
                swap(arr,i,minIndex);
            }
        }
    }
    private static void swap(int[] arr, int i, int j) {
        arr[i]=arr[i]^arr[j];
        arr[j]=arr[i]^arr[j];
        arr[i]=arr[i]^arr[j];
    }
    public static void main(String[] args) {
        int[]arr={2,3,43,4,5,67,84,3,22,35,64};
        selectionSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}
}

例子三

插入排序的細節講解與複雜度分析
時間複雜度O(N^2),額外空間複雜度O(1)
測試

/**
 * 插入排序:時間複雜度O(N^2)
 * 測試數組: int[] arr={2,4,6,7,4,333};
 * 排序邏輯:
 *  一、先0-1開始,若是前面那個元素大於後面那個元素,就進行交換,交換後前面那個元素是小的
 *  二、再從1-2比較兩個元素,前一個元素小於後一個元素進行交換,再0-1比較重複步驟2
 *  三、再從2-3.。。arr.length-2-array.length-1比較.....
 *  排序過程:
 *  一、[2,4,|6,7,4,333]
 *  二、[2,4,6,|7,4,333]
 *  三、[2,4,6,7,|4,333]
 *  四、[2,4,6,4,7,|333]
 *     [2,4,4,6,7,333]
 *  五、[2,4,4,6,7,333]
 */
public class InsertSort {

    public static void insertionSort(int[] arr){
        if (arr==null || arr.length<2){
            return;
        }
        for (int i = 1; i < arr.length; i++) {
            for (int j = i-1; j >=0&&arr[j]>arr[j+1]; j--) {
                swap(arr,j,j+1);
            }
        }
    }

    private static void swap(int[] arr, int i, int j) {
        arr[i]=arr[i]^arr[j];
        arr[j]=arr[i]^arr[j];
        arr[i]=arr[i]^arr[j];
    }

    public static void main(String[] args) {
        int[] arr={2,4,6,7,4,333};
        insertionSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

剖析遞歸行爲和遞歸行爲時間複雜度的估算
一個遞歸行爲的例子
master公式的使用
spa

T(N) = a*T(N/b) + O(N^d)
1) log(b,a) > d -> 複雜度爲O(N^log(b,a))
htm

2) log(b,a) = d -> 複雜度爲O(N^d * logN) blog

3) log(b,a) < d -> 複雜度爲O(N^d)
補充閱讀:www.gocalf.com/blog/algorithm-complexity-and-mastertheorem.html排序

例子四

歸併排序的細節講解與複雜度分析
時間複雜度O(N*logN),額外空間複雜度O(N)
遞歸

/**
 * 二分遞歸歸併排序:時間複雜度:O(N*logN)額外空間複雜度O(N)
 * 測試數組:  int[] arr={1,3,3,6,7,4};
 * 排序邏輯:
 *  一、[1,3,3],[6,7,4]
 *  二、[1,3],[3]  ,[6,7],[4]
 *  三、[1,3,3]  ,[4,6,7]
 *  四、[1,3,3,4,6,7]
 */
public class MergeSort {
    public static void mergeSort(int[] arr){
        if (arr==null || arr.length<2){
            return;
        }
        mergeSort(arr,0,arr.length-1);
    }

    private static void mergeSort(int[] arr, int left, int right) {
        if (left==right){
            return;
        }
        int mid =left+((right-left)>>1);
        mergeSort(arr,left,mid);
        mergeSort(arr,mid+1,right);
        mergeSort(arr,left,mid,right);
    }

    private static void mergeSort(int[] arr, int left, int mid, int right) {
        int[] help=new int[right-left+1];
        int i=0;
        int p1=left;
        int p2=mid+1;
        while (p1<=mid && p2<=right){
            help[i++]=arr[p1]<arr[p2]?arr[p1++]:arr[p2++];
        }
        while (p1<=mid){
            help[i++]=arr[p1++];
        }
        while (p2<=right){
            help[i++]=arr[p2++];
        }
        for (int j = 0; j < help.length; j++) {
            //二分後每一個小的數組的left
            arr[left+j]=help[j];
        }
    }

    public static void main(String[] args) {
        int[] arr={1,3,3,6,7,4};
        mergeSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

例子wu

小和問題和逆序對問題
小和問題
在一個數組中,每個數左邊比當前數小的數累加起來,叫作這個數組的小和。求一個數組 的小和。
例子:rem

[1,3,4,2,5]

1左邊比1小的數,沒有;

3左邊比3小的數,1;

4左邊比4小的數,一、3;

2左邊比2小的數,1;

5左邊比5小的數,一、三、四、2;

因此小和爲1+1+3+1+1+3+4+2=16
逆序對問題 在一個數組中,左邊的數若是比右邊的數大,則折兩個數構成一個逆序對,請打印全部逆序 對。

/**
 * 小和問題
 */
public class SmallSum {
    public static int smallSum(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }
        return mergeSort(arr, 0, arr.length - 1);
    }

    public static int mergeSort(int[] arr, int l, int r) {
        if (l == r) {
            return 0;
        }
        int mid = l + ((r - l) >> 1);
        return mergeSort(arr, l, mid) + mergeSort(arr, mid + 1, r) + merge(arr, l, mid, r);
    }

    public static int merge(int[] arr, int l, int m, int r) {
        int[] help = new int[r - l + 1];
        int i = 0;
        int p1 = l;
        int p2 = m + 1;
        int res = 0;
        while (p1 <= m && p2 <= r) {
            res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0;
            help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
        }
        while (p1 <= m) {
            help[i++] = arr[p1++];
        }
        while (p2 <= r) {
            help[i++] = arr[p2++];
        }
        for (i = 0; i < help.length; i++) {
            arr[l + i] = help[i];
        }
        return res;
    }

    public static void main(String[] args) {
        int [] arr={1,2,3,4,5,6,7,8};
        smallSum(arr);
        System.out.println(Arrays.toString(arr));
    }
}

本文參考:牛客網

相關文章
相關標籤/搜索