《算法導論》個人筆記(一)


今天的筆記是第一部分:基礎知識中的第1、2章內容。先來個概述,第一章主要介紹算法是什么,算法在計算中能起到什么作用。第二章主要介紹算法基礎,講了一個插入排序算法,同時介紹了如何分析算法的復雜度,還引入了分治法的思想,歸並排序算法。另,包含一些練習題。
一、算法
  1. 算法是什么
        算法就是任何定義良好的計算過程,它取一個或一組值作為輸入,並產生出一個或一組值作為輸出。也就是說,算法就是一系列的計算過程,用來將輸入的數據轉換成輸出結果。
        例如:我們需要把一個數列按照非遞減排序。下面是關於排序問題的形式定義。
        輸入:n個數的一個序列{a1,a2,a3,a4,…,an}。
       輸出:輸入序列的一個排列{a1’,a2’,a3’,a4’,…,an’},滿足a1’<= a2’ <= a3’ … <= an’。
  2. 算法的應用
  3. 以上咱們使用算法解決排序問題,但是算法實際應用無處不在。例如:
    • 分析數據庫中存儲的人類基因工程中30億個化學基對的序列
    • 管理和處理互聯網上的海量數據,訪問與檢索大量信息
    • 電子商務對個人訂單信息保密,核心技術是公鑰密碼和數字簽名
二、算法基礎
1、插入排序法
  • 插入排序是一個對少量元素進行排序的有效算法。
    我們將其偽代碼過程命名為INSERTION-SORT,它的參數是一個數組A[1 .. n],包含了n個待排數字。
    (在偽代碼中,A中元素的個數n用A.length來表示)
    算法思想:每趟將一個元素,按照其中元素的大小插入到它前面已經排序的子序列中,依此重復,直到插入全部元素。
        **INSERTION-SORT(A)**
        for j = 2 to A.length
            key = A[j]
            // Insert A[j] into the sorted sequence A[1 .. j - 1]
            i = j - 1
            while i > 0 and A[i] > key
                A[i + 1] = A[i]
                i = i - 1
            A[i + 1] = key
    
  • 插入排序算法的簡單Java實現
     
       /**
         * 插入排序
         *
         * @param array
         */
        public static void insertionSort(int[] array) {
            int key, j;
            for (int i = 1; i < array.length; i++) {
                key = array[i];
                j = i - 1;
                while (j >= 0 && array[j] > key) {
                    array[j + 1] = array[j];
                    j--;
                }
                array[j + 1] = key;
            }
        }
    
  • 算法分析

        算法分析是指對一個算法所需要的資源進行預測。內存,通信帶寬或計算機硬件等資源偶爾會是我們主要關心的,但通常,資源是指我們希望度量的是計算時間。
        我們就不把插入排序算法的分析過程一一貼出來了,插入排序算法的時間復雜度是T(n)=O(n*n)。

2、分治思想
  • 將原問題分解為幾個規模較小但類似於原問題的子問題,遞歸地求解這些子問題。然后再合並這些子問題的解來建立原問題的解。
    分治模式在每層l遞歸時都有三個步驟:
    • 分解原問題為若干子問題,這些子問題是原問題的規模較小的實例。
    • 解決這些子問題,遞歸地求解各個子問題。然而,若子問題的規模足夠小,則直接求解。
    • 合並這些子問題的解成原問題的解。
  • 歸並排序算法
    歸並排序算法完全遵循分治模式。 直觀上操作如下:
    • 分解:將 n 個元素分成各含 n / 2個元素的子序列;
    • 解決:用歸並排序法對兩個子序列遞歸地排序;
    • 合並:合並兩個已排序的子序列以得到排序結果。
        對子序列排序時,其長度為1時遞歸”開始回升”。在這種情況下不要做任何工作,因為長度為1的每個序列都已排好序。歸並排序的關鍵步驟在於合並兩個已排序的子序列。
        這里引入一個輔助過程MERGE(A, p, q, r),其中A為數組,p,q和r都是下標,有p <= q < r。該過程假設子數組A[p .. q]和A[q+1 .. r]都已排好序,並將它們合並成一個已排好序的子數組代替當前子數組A[p .. r]。
  • 歸並排序算法的實現
    合並步驟:
    MERGE(A, p, q, r)
       n1 = q - p + 1
       n2 = r - q
       let L[1 .. n1 + 1] and R[1 .. n2 + 1] be new arrays
       for i = 1 to n1
           L[i] = A[p + i - 1]
       for j = 1 to n2
           R[j] = A[q + j]
       L[n1 + 1] = MAX
       R[n2 + 1] = MAX
       i = 1
       j = 1
       for k = p to r
           if L[i] <= R[j]
               A[k] = L[i]
               i = i + 1
           else
               A[k] = R[j]
               j = j + 1
    
    排序步驟:
        MERGE(A, p, q, r)
        n1 = q - p + 1
        n2 = r - q
        let L[1 .. n1 + 1] and R[1 .. n2 + 1] be new arrays
        for i = 1 to n1
            L[i] = A[p + i - 1]
        for j = 1 to n2
            R[j] = A[q + j]
        L[n1 + 1] = MAX
        R[n2 + 1] = MAX
        i = 1
        j = 1
        for k = p to r
            if L[i] <= R[j]
                A[k] = L[i]
                i = i + 1
            else 
                A[k] = R[j]
                j = j + 1
    
  • 歸並排序算法Java實現
        /**
        * 歸並排序
        *
        * @param array
        */
        public static void mergeSort(int[] array) {
            mergeSort(array, 0, array.length - 1);
        }
    
        private static void mergeSort(int[] array, int p, int r) {
            int q;
            if (p < r) {
                q = (p + r) >> 1;
                mergeSort(array, p, q);
                mergeSort(array, q + 1, r);
                merge(array, p, q, r);
            }
        }
    
        private static void merge(int[] array, int p, int q, int r) {
            int lLen = q - p + 1;
            int rLen = r - q;
            int[] left = new int[lLen + 1];
            int[] right = new int[rLen + 1];
            int i, j;
            for (i = 0; i < lLen; i++)
                left[i] = array[p + i];
            for (j = 0; j < rLen; j++)
                right[j] = array[q + j + 1];
            left[i] = Integer.MAX_VALUE;
            right[j] = Integer.MAX_VALUE;
            i = j = 0;
            for (int k = p; k <= r; k++) {
                if (left[i] <= right[j])
                    array[k] = left[i++];
                else
                    array[k] = right[j++];
            }
        }
    
習題
  1. 插入排序改寫成遞歸過程
    INSERTION-SORT-RECURSIVE(A, p)
        if p > 1
            key = A[p]
            p = p - 1
            INSERTION-SORT-RECURSIVE(A, p)
            INSERTION-ELEMENT(A, p, key)
    
    INSERTION-ELEMENT(A, p, key)
        while p > 0 and A[p] > key
            A[p + 1] = A[p]
            p = p - 1
        A[p + 1] = key
    
  2. 二分查找偽碼
    **BINARY-SEARCH(A, v)**
        front = 1
        end = A.length
        while front < end
            middle = (front + end) / 2
            if A[middle] < v
                front = middle + 1
            else if A[middle] > v
                end = middle - 1
            else
                return middle
        return -1
    
  3. 設計算法:查找集合S中是否存在兩個元素和等於x的元素。
    思路:先排序,后查找
    **CHECK-SUM(S, x)**
        A = MERGE-SORT(S)
        for i = 1 to A.length
            v = x - A[i]
            if BINARY-SEARCH(A, v) > 0
                return true
        return false
    
感謝大家花時間閱讀本人博客,在接下來每周會更新一篇算法導論的算法設計博文。當中有什么問題還請大家指正,相互學習,相互促進!


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com