數據結構與算法筆記 - 緒論

數據結構與算法筆記 - 緒論

 

1. 什麼是計算
2. 評判DSA優劣的參照(直尺)
3. 度量DSA性能的尺度(刻度)
4. DSA的性能度量的方法
5. DSA性能的設計及其優化html

x1. 理論模型與實際性能的差別
x2. DSA優化的極限(下界)ios

 

計算機與算法

計算機科學(computer science)的核心在於研究計算方法與過程的規律,而不只僅是做爲計算工具的計算機自己,所以E. Dijkstra及其追隨者更傾向於將這門科學稱做計算科學(computing science)。算法

計算 = 信息處理數組

計算模型 = 計算機 = 信息處理工具數據結構

1. 計算機的本質是計算,計算是尋找對象的規律,並從中找到技巧。計算的目標是高效,低耗。函數

2. 算法就是藉助必定的工具,在必定的規則下,以明確而機械的形式來進行的計算。
算法定義:基於特定的計算類型,旨在解決某一信息處理問題而設計的一個指令序列。工具

3. 算法需具有如下要素
        輸入與輸出
                輸入(input):對所求解問題特定實例的描述
                輸出(output):經計算和處理以後獲得的信息,即針對輸入問題實例的答案
        肯定性和可行性:算法應可描述爲由若干語義明確的基本操做組成的指令序列,且每一基本操做在對應的計算模型中都可兌現。
        有窮性:任意算法都應在執行有限次基本操做以後終止並給出輸出
        正確性:算法所給的輸出應該可以符合由問題自己在事先肯定的條件
        退化和魯棒性:例如算法數據的各類極端的輸入實例都屬於退化(degeneracy)狀況,魯棒性(robustness)要求儘量充分地應對此類狀況。
        重用性:算法模式可推廣並適用於不一樣類型基本元素的特性性能

 

證實算法的有窮性和正確性:從適當的角度審視整個計算過程,找出其所具備的某種不變性和單調性
        單調性:問題的有效規模會隨着算法的推動不斷遞減
        不變性:不只應在算法初始狀態下天然知足,並且應與最終的正確性相呼應----當問題的規模縮減到0時,不變性應隨即等價於正確性
        例如, 冒泡排序的正確性證實:(不變性)通過k趟掃描交換後,最大的前k個元素必然就位;(有窮性)通過k趟掃描交換後,待求解問題的有效規模將縮減至n-k。測試

 

好的算法:效率最高(速度儘量快,存儲空間儘量少)同時又兼顧正確(算法可以正確地解決問題)、健壯(容錯性好)、可讀(易於閱讀)。 相似既要馬兒跑的快,又要吃的少。優化

算法 + 數據結構 = 程序         (算法 + 數據結構) * 效率 = 計算

 

計算模型

1. 一個好的程序不只要考慮數據結構與算法,還要考慮效率,即:(數據結構+算法)*效率 = 程序 => 應用。

2. 算法分析的兩個重要指標 (須要進行度量)
        正確性:算法功能是否與問題一致
        成本:時間消耗與存儲空間消耗

3. 定義:T(n) 爲一個算法在最壞的狀況下所須要操做的步驟。不一樣算法之間的好壞主要看T(n)的大小,T(n)是屏蔽了計算機硬件差別,語言差別,編譯差別等差別以後的理想平臺下的運行指標,如大O,大Ω,大Θ等。

4. 通常的計算模型有圖靈模型與RAM模型,它們均將算法的運算時間轉換成算法執行的基本操做次數。

 

圖靈機模型

圖靈機的三個組成要件
        1. 有限的字母表: cell中存儲的內容
        2. 讀寫頭: 只是當前位置, 可讀可寫
        3. 狀態表: 當前讀寫頭的狀態

圖靈機狀態轉換過程 transform(q,c; d,L/R,p)
        q:當前狀態
        c:讀寫頭所指cell當前的內容
        d:讀寫頭所指cell改寫的內容
        L/R:向左/右移位
        p:讀寫頭轉換後的狀態

 

RAM 模型

1. 與圖靈機相似,均假設有無限空間
2. 由一系列順序編號寄存器組成,但總數無限
3. 算法所運行的時間轉換成算法運算時的次數

 

數據結構

數據結構示意

        數據對象由數據元素組成,數據元素由數據項組成,數據項是最基本的單位
        數據結構指數據對象中數據元素之間的關係
        數據結構主要研究非數值計算程序問題中的操做對象以及它們之間的關係

數據結構的邏輯結構

        集合結構
        線性結構
        樹結構
        圖結構

數據結構的物理結構

        順序存儲結構
        鏈式存儲結構

數據的運算

        插入
        刪除
        修改
        查找
        排序

 

複雜度度量

1. 算法的效率主要看時間消耗與存儲空間消耗,這裏咱們屏蔽存儲空間的消耗,僅僅考慮時間的消耗。

2. 大O的定義:T(n)=O(f(n)) ,f(n)爲一個函數。當c>0,T(n)<c∗f(n),即大O記號表示T(n)的一個上界,其性質爲:
        O(n)=O(c∗n)
        O(n^2+n)=O(n^2)

3. 大Ω的定義:T(n)=Ω(f(n)) ,f(n)爲一個函數。當c>0,T(n)>c∗f(n),即大O記號表示T(n)的一個下界。

4. 大Θ的定義:T(n)=Θ(f(n)) ,f(n)爲一個函數。當c1>c2>0,c1∗f(n)>T(n)>c2∗f(n),即大O記號表示T(n)的一個區間。

5. 大O記號的分類:
        常數類:O(1)=2 or222222 ,有效
        對數類:O(log^c n)與常底數、常數次冪無關,複雜度接近常數,有效。
        多項式:O(n^c)
        線性:O(n)
        指數:c^n=O(2^n)任何c都可。成本增加極快,不是有效的。

6. 時間複雜度T(n) :特定算法處理規模爲n的問題所需的時間,因爲n相同,但T(n)不一樣,---->簡化爲:
                                        在規模爲n的全部輸入中選擇時間最長者做爲T(n),並以T(n)度量算法的時間複雜度。

7. 漸進時間複雜度:注重時間複雜度隨問題規模n的增加的整體變化趨勢
        大O記號(T(n)的漸進上界):
                若存在正的常數c和函數f(n),使的對任何n>>2都有: T(n) <= c * f(n),即認爲在n足夠大以後,f(n)給出了T(n)增加速度的一個漸進上界,記爲:T(n) = O( f(n) )

8. 大O記號性質:
        對於任一常數 c > 0, 有O( f(n) ) = O( c * f(n) ):在大O記號意義下:函數各項正的常係數能夠忽略並等同於1
        對於任意常數 a > b > 0,有 O( n ^ a + n ^ b ) = O( n ^ a ):在大O記號意義下:多項式中的低次項都可忽略

9. 空間複雜度(Space Complexity)是對一個算法在運行過程當中臨時佔用存儲空間大小的量度。一個算法在計算機存儲器上所佔用的存儲空間,包括存儲算法自己所佔用的存儲空間,算法的輸入輸出數據所佔用的存儲空間和算法在運行過程當中臨時佔用的存儲空間這三個方面。

        算法的空間複雜度經過計算算法所需的存儲空間實現,算法空間複雜度的計算公式記做:S(n)= O(f(n)),其中,n爲問題的規模,f(n)爲語句關於n所佔存儲空間的函數。

        通常狀況下,一個程序在機器上執行時,除了須要存儲程序自己的指令、常數、變量和輸入數據外,還須要存儲對數據操做的存儲單元。若輸入數據所佔空間只取決於問題自己,和算法無關,這樣只須要分析該算法在實現時所需的輔助單元便可。若算法執行時所需的輔助空間相對於輸入數據量而言是個常數,則稱此算法爲原地工做,空間複雜度爲O(1)。

        關於O(1)的問題, O(1)是說數據規模和臨時變量數目無關,並非說僅僅定義一個臨時變量。舉例:不管數據規模多大,我都定義100個變量,這就叫作數據規模和臨時變量數目無關。就是說空間複雜度是O(1)。

        當一個算法的空間複雜度爲一個常量,即不隨被處理數據量n的大小而改變時,可表示爲O(1);當一個算法的空間複雜度與以2爲底的n的對數成正比時,可表示爲0(10g2n);當一個算法的空I司複雜度與n成線性比例關係時,可表示爲0(n).若形參爲數組,則只須要爲它分配一個存儲由實參傳送來的一個地址指針的空間,即一個機器字長空間;若形參爲引用方式,則也只須要爲其分配存儲一個地址的空間,用它來存儲對應實參變量的地址,以便由系統自動引用實參變量。

10. 對於一個算法,其時間複雜度和空間複雜度每每是相互影響的。當追求一個較好的時間複雜度時,可能會使空間複雜度的性能變差,便可能致使佔用較多的存儲空間;反之,求一個較好的空間複雜度時,可能會使時間複雜度的性能變差,便可能致使佔用較長的運行時間。另外,算法的全部性能之間都存在着或多或少的相互影響。所以,當設計一個算法(特別是大型算法)時,要綜合考慮算法的各項性能,算法的使用頻率,算法處理的數據量的大小,算法描述語言的特性,算法運行的機器系統環境等各方面因素,纔可以設計出比較好的算法。

11. 一般,咱們都使用「時間複雜度」來指運行時間的需求,使用「空間複雜度」指空間需求。當不用限定詞地使用「複雜度」時,一般都是指時間複雜度。

 

算法分析

1. 算法分析主要有兩個任務: 

        正確性

        複雜度

2. 複雜度的分析方法有三種: 

        迭代式算法:級數求和

        遞歸式算法:遞歸跟蹤 + 遞歸方程

        猜想 + 驗證

3. 算數級數:與末項的平方同階 

4. 冪方級數:比冪次高出一階 

5. 幾何級數(a>1):與末項同階 

6. 收斂級數:O(1)

7. 可能未必收斂,但長度有限 

8. 循環:通常隨着層數的增長指數式增加

9. 遞歸跟蹤分析:檢查每一個遞歸實例,累計所需時間(調入語句自己,計入對應的子實例),總和即爲算法執行時間。

 

 

迭代與遞歸

算法的兩種思想方法:分而治之,減而治之。
        分而治之:將一個問題分兩個規模大小差很少的子問題。
        減而治之:將一個問題分爲一個子問題和一個規模縮減的問題。

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <algorithm>

// 問題: 計算任意n個整數之和

// 實現: 使用迭代的方法, 逐一取出每一個元素, 累加之
// 時間複雜度: T(n) = 1 + n * 1 + 1 = n + 2 = O(n)
// 空間複雜度: S(n) = 1 + 1 = 2 = O(1)
int SumA(int A[], int n)
{
    int sum = 0;
    for (int i = 0; i < n; i++)
    {
        sum += A[i];
    }
    return sum;
}

// 實現: 使用線性遞歸的方法
// 時間複雜度: T(n) = O(1) * (n+1) = O(n)
// 空間複雜度: S(n) = O(1) * (n+1) = O(n)
int SumB(int A[], int n)
{
    return (1 > n) ? 0 : A[n-1] + SumB(A, n-1);
}

// 實現: 二分遞歸的方法
// 時間複雜度: T(n) = O(1) * (2^0 + 2^1 + 2^2 + ... + 2^log.n) = O(1) + (2^log.(n+1) -1) = O(n)
// 空間複雜度: S(n) = O(1) * (2^0 + 2^1 + 2^2 + ... + 2^log.n) = O(1) + (2^log.(n+1) -1) = O(n)
int SumC(int A[], int lo, int hi) // 區間範圍A[lo, hi] 調用方式爲SumC(A, 0, n -1)
{
    if (lo == hi) // 如遇遞歸基(區間長度已降至1), 則
    {
        return A[lo]; // 直接返回改元素
    }
    else // 不然 ( 通常狀況下 lo < hi ), 則
    {
        int mi = (lo + hi) >> 1; // 以居中單元爲界,將原區間一分爲二
        return SumC(A, lo, mi) + SumC(A, mi + 1, hi); // 遞歸對各個子數組求和, 而後合計
    }
}

// 任給數組A[0, n), 降其先後顛倒
// 實現: 使用遞歸的方法
// 時間複雜度: T(n) = (hi - lo) / 2 = n/2 = O(n)
// 空間複雜度: S(n) = O(n)
void reverseA(int A[], int lo, int hi) // 區間範圍A[lo, hi] 調用方式爲reverseA(A, 0, n -1)
{
    if (lo < hi)
    {
        // std::swap 須要引入 algorithm 頭文件
        // 問題規模的奇偶性不變, 須要兩個遞歸基
        std::swap(A[lo], A[hi]); // 交換A[lo]和A[hi]
        reverseA(A, lo+1, hi-1); //遞歸倒置 A(lo, hi)
    }
    else // 隱含了兩種遞歸基
    {
        return;
    }
}

// 任給數組A[0, n), 降其先後顛倒
// 實現: 使用迭代的方法
// 時間複雜度: T(n) = (hi - lo) / 2 = n/2 = O(n)
// 空間複雜度: S(n) = O(1)
void reverseB(int A[], int lo, int hi) // 區間範圍A[lo, hi] 調用方式爲reverseA(A, 0, n -1)
{
    while (lo < hi) // 用while替換跳轉標誌和if,徹底等效
    {
        std::swap(A[lo++], A[hi--]); // 交換A[lo]和A[hi],收縮待倒置匙間
    }
}


int main()
{
    int iArray[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
    std::cout << SumA(iArray, sizeof(iArray)/sizeof(iArray[0])) << std::endl; // 210
    std::cout << SumB(iArray, sizeof(iArray)/sizeof(iArray[0])) << std::endl; // 210
    std::cout << SumC(iArray, 0, sizeof(iArray)/sizeof(iArray[0]) - 1) << std::endl; // 210

    reverseA(iArray, 0, sizeof(iArray)/sizeof(iArray[0]) - 1); // 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
    for (auto a : iArray)
    {
        std::cout << a << " ";
    }
    std::cout << std::endl;

    reverseB(iArray, 0, sizeof(iArray)/sizeof(iArray[0]) - 1); // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
    for (auto a : iArray)
    {
        std::cout << a << " ";
    }
    std::cout << std::endl;

    system("pause");
    return 0;
}

 

動態規劃

1. 動態規劃的目的:
        make it work(遞歸能夠保證)
        make it right(遞歸能夠保證)
        make it fast(迭代能夠保證)
2. 遞歸對於資源的消耗大並且O(n)比較大,然而迭代能夠下降對存儲空間的使用,有時亦能夠下降O(n)
3. 子序列:由原序列中若干個元素,按原來相對次序排列而成的新的序列。
4. 最長公共子序列(longest common subsequence, LCS)是兩個序列中,在其相同的子序列中長度最長的那個子序列,可能含有多個。

 

動態規劃的方法改良Fib的算法:

int fib (int n)
{
    int i =1, f = 0, g = 1;
    while(++i < n/2)
    {
        f = f + g; //計算奇數項
        g = f + g; //計算偶數項
    }
    return(n % 2) ? f: g; //n爲奇數時返回f,偶數時返回g
}

 

遞歸版最長公共子串:

int lcs (string a, string b)
{
    int m,n;
    m =a.size();
    n =b.size();
    stringc, d;
    for (inti = 0; i < m - 1; i++) //取a串的(m-1)個字符
        c[i] = a[i];
    for (intj = 0; j < n - 1; j++) //取b串的(n-1)個字符
        d[j] = b[j];
    if (a[m-1]== b[n-1])
        return lcs(c, d) + 1; //當a[m-1]等於b[n-1]時,長度計數加一
    else
        return (lcs(a,d) > lcs (b,c)) ? lcs(a, d): lcs(b, c);//當兩個子串的lcs長度不一樣時,長度計數取更大者
}

 

使用動態規劃的思想求解最長公共子串:

int lcs (string a, string b, const int m,const int n) //m=a.size()+1, n=b,size()+1
{
    intacc[m][n] = { 0 };
    inti, j
        for(i = 1; i < m - 1; i++)
            for(j = 1; j < n - 1; j++)
            {
                if(acc[i][j-1] == acc[i-1][j])
                {
                    if(a[i] == b[j])
                        acc[i][j]= acc[i][j-1] + 1; //當a[i]等於b[j]時,長度計數加一
                    else
                        acc[i][j]= acc[i][j-1]; //當兩者不等時,長度計數不變
                }
                else
                    acc[i][j]= (acc[i][j-1] > acc[i-1][j]) ? acc[i][j-1]: acc[i-1][j];//當兩個子串的lcs長度不一樣時,長度計數取更大者
            }
}

 

Fib() 遞歸方程的封底估算

        FLOPS(即「每秒浮點運算次數」,「每秒峯值速度」),是「每秒所執行的浮點運算次數」(floating-point operations per second)的縮寫。它常被用來估算電腦的執行效能,尤爲是在使用到大量浮點運算的科學計算領域中。正由於FLOPS字尾的那個S,表明秒,而不是複數,因此不能省略掉。

        在這裏所謂的「浮點運算」,實際上包括了全部涉及小數的運算。這類運算在某類應用軟件中經常出現,而它們也比整數運算更花時間。現今大部分的處理器中,都有一個專門用來處理浮點運算的「浮點運算器」(FPU)。也所以FLOPS所量測的,實際上就是FPU的執行速度。而最經常使用來測量FLOPS的基準程式(benchmark)之一,就是Linpack。

        1GHz 就是每秒十億次(=10^9)運算,若是每次運算能完成兩個浮點操做,就叫 2G FLOPS(每秒二十億次浮點操做)。如今家用的雙核計算機一般都能達到每秒四十億次運算(2*2.0GHz)左右的水平,浮點性能大約是上百億次(=10^10)浮點操做。 

 

 

__int64 Fib::fib(int n) // 計算Fibonacci數列的第n項(二分遞歸版):O(2^n)
{
    return ( 2 > n ) ?
        ( __int64 ) n // 若到達遞歸基,直接取值
        : fib ( n - 1 ) + fib ( n - 2 ); // 不然,遞歸計算前兩項,其和即爲正解
}

 

printf ( "\n------------- Binary Recursion -------------\n" );
for (int i = 0; i < n; i++)
{
    start = clock();
    printf("fib(%2d) = %22I64d\n", i, f.fib(i)); // T(n) = O(2^n)
    finish = clock();
    duration = (double)(finish - start) / CLOCKS_PER_SEC;
    printf(">>> Time: %2.3f seconds\n", duration);
}

 

計算f(35)所需的時間

------------- Binary Recursion -------------
fib( 0) =                      0
>>> Time: 0.000 seconds
fib( 1) =                      1
>>> Time: 0.000 seconds
fib( 2) =                      1
>>> Time: 0.000 seconds
fib( 3) =                      2
>>> Time: 0.000 seconds
fib( 4) =                      3
>>> Time: 0.000 seconds
fib( 5) =                      5
>>> Time: 0.000 seconds
fib( 6) =                      8
>>> Time: 0.000 seconds
fib( 7) =                     13
>>> Time: 0.000 seconds
fib( 8) =                     21
>>> Time: 0.000 seconds
fib( 9) =                     34
>>> Time: 0.000 seconds
fib(10) =                     55
>>> Time: 0.000 seconds
fib(11) =                     89
>>> Time: 0.000 seconds
fib(12) =                    144
>>> Time: 0.000 seconds
fib(13) =                    233
>>> Time: 0.000 seconds
fib(14) =                    377
>>> Time: 0.000 seconds
fib(15) =                    610
>>> Time: 0.000 seconds
fib(16) =                    987
>>> Time: 0.000 seconds
fib(17) =                   1597
>>> Time: 0.000 seconds
fib(18) =                   2584
>>> Time: 0.000 seconds
fib(19) =                   4181
>>> Time: 0.000 seconds
fib(20) =                   6765
>>> Time: 0.000 seconds
fib(21) =                  10946
>>> Time: 0.000 seconds
fib(22) =                  17711
>>> Time: 0.000 seconds
fib(23) =                  28657
>>> Time: 0.000 seconds
fib(24) =                  46368
>>> Time: 0.015 seconds
fib(25) =                  75025
>>> Time: 0.016 seconds
fib(26) =                 121393
>>> Time: 0.015 seconds
fib(27) =                 196418
>>> Time: 0.032 seconds
fib(28) =                 317811
>>> Time: 0.046 seconds
fib(29) =                 514229
>>> Time: 0.094 seconds
fib(30) =                 832040
>>> Time: 0.125 seconds
fib(31) =                1346269
>>> Time: 0.218 seconds
fib(32) =                2178309
>>> Time: 0.359 seconds
fib(33) =                3524578
>>> Time: 0.562 seconds
fib(34) =                5702887
>>> Time: 1.092 seconds
fib(35) =                9227465
>>> Time: 1.542 seconds
fib(36) =               14930352
>>> Time: 2.477 seconds
fib(37) =               24157817
>>> Time: 4.007 seconds
fib(38) =               39088169
>>> Time: 6.281 seconds
fib(39) =               63245986
>>> Time: 10.394 seconds
fib(40) =              102334155
>>> Time: 17.638 seconds
fib(41) =              165580141
>>> Time: 36.837 seconds
fib(42) =              267914296
>>> Time: 52.502 seconds

Return Value: 0
請按任意鍵繼續. . . 

 

 

        Ο(1)表示基本語句的執行次數是一個常數,通常來講,只要算法中不存在循環語句,其時間複雜度就是Ο(1)。其中Ο(log2n)、Ο(n)、 Ο(nlog2n)、Ο(n2)和Ο(n3)稱爲多項式時間,而Ο(2n)和Ο(n!)稱爲指數時間。計算機科學家廣泛認爲前者(即多項式時間複雜度的算法)是有效算法,把這類問題稱爲P(Polynomial,多項式)類問題,而把後者(即指數時間複雜度的算法)稱爲NP(Non-Deterministic Polynomial, 非肯定多項式)問題

 

Fibonacci 部分的測試源代碼及測試輸出:

/* Start of Fib.h */

#ifndef __FIB_H__
#define __FIB_H__

class Fib // Fibonacci數列類
{
private:
    int f, g; // f = fib(k - 1), g = fib(k)。均爲int型,很快就會數值溢出
    
public:
    Fib(int n); // 初始化爲不小於n的最小Fibonacci項
    int get(); // 獲取當前Fibonacci項,O(1)時間
    int next(); // 轉至下一Fibonacci項,O(1)時間
    int prev(); // 轉至上一Fibonacci項,O(1)時間

    __int64 fibI(int n); // 計算Fibonacci數列的第n項(迭代版):O(n)
    __int64 fib(int n); // 計算Fibonacci數列的第n項(二分遞歸版):O(2^n)
    __int64 fib(int n, __int64 & prev);  // 計算Fibonacci數列第n項(線性遞歸版):入口形式fib(n, prev)
};

#endif // !__FIB_H__

/* End of Fib.h */

 

/* Start of Fib.cpp */

#include "Fib.h"

// fib(-1), fib(0),O(log_phi(n))時間
Fib::Fib(int n)
{
    f = 1;
    g = 0;
    while (g < n)
    {
        next();
    }
}

__int64 Fib::fibI(int n) // 計算Fibonacci數列的第n項(迭代版):O(n)
{
    __int64 f = 1, g = 0;
    while (0 < n--)
    { // 依據原始定義,經過n次加法和減法計算fib(n)
        g += f;
        f = g - f;
    }
    return g;
}

__int64 Fib::fib(int n) // 計算Fibonacci數列的第n項(二分遞歸版):O(2^n)
{
    return ( 2 > n ) ?
        ( __int64 ) n // 若到達遞歸基,直接取值
        : fib ( n - 1 ) + fib ( n - 2 ); // 不然,遞歸計算前兩項,其和即爲正解
}

__int64 Fib::fib(int n, __int64 & prev)  // 計算Fibonacci數列第n項(線性遞歸版):入口形式fib(n, prev)
{
    if ( 0 == n ) // 若到達遞歸基,則
    { 
        prev = 1;
        return 0;
    } // 直接取值:fib(-1) = 1, fib(0) = 0
    else 
    { // 不然
        __int64 prevPrev;
        prev = fib(n - 1, prevPrev ); // 遞歸計算前兩項
        return prevPrev + prev; //其和即爲正解
    }
} // 用輔助變量記錄前一項,返回數列的當前項,O(n)

// 獲取當前Fibonacci項,O(1)時間
int Fib::get()
{
    return g;
}

// 轉至下一Fibonacci項,O(1)時間
int Fib::next()
{
    g += f;
    f = g - f;
    return g;
}

// 轉至上一Fibonacci項,O(1)時間
int Fib::prev()
{
    f = g -f;
    g -= f;
    return g;
}

/* End of Fib.cpp */

 

/* Start of mytest.cpp */

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <ctime>
#include <algorithm>

#include "Fib.h"


int mytest(int argc, char * argv[])
{
    // clock_t實際爲long類型
    // 常量CLOCKS_PER_SEC 表示每一秒(per second)有多少個時鐘計時單元
    clock_t start, finish;
    double  duration;

    int n = 36; // Rank Value

    // 檢查參數
    if (2 > argc)
    { 
        fprintf ( stderr, "Usage: %s <rank>\n", argv[0] );
    } 
    else
    {
        n = atoi(argv[1]);
    }

    // 依次計算Fibonacci數列各項
    Fib f(0);

    start = clock();
    printf("\n------------- class Fib -------------\n");
    for (int i = 0; i < n; i++, f.next())
    {
        printf( "fib(%2d) = %d\n", i, f.get()); // T(n) = O(n)
    }
    finish = clock();
    duration = (double)(finish - start) / CLOCKS_PER_SEC;
    printf(">>> Time: %2.3f seconds\n", duration);

    start = clock();
    for (int i = 0; i <= n; i++, f.prev())
    {
        printf ("fib(%2d) = %d\n", n - i, f.get()); // T(n) = O(n)
    }
    finish = clock();
    duration = (double)(finish - start) / CLOCKS_PER_SEC;
    printf(">>> Time: %2.3f seconds\n", duration);

    start = clock();
    printf ("\n------------- Iteration -------------\n");
    for (int i = 0; i < n; i++)
    {
        printf("fib(%2d) = %22I64d\n", i, f.fibI(i)); // T(n) = O(n^2)
    }
    finish = clock();
    duration = (double)(finish - start) / CLOCKS_PER_SEC;
    printf(">>> Time: %2.3f seconds\n", duration);

    start = clock();
    printf ( "\n------------- Linear Recursion -------------\n" );
    for (int i = 0; i < n; i++)
    {
        __int64 fp;
        printf ( "fib(%2d) = %22I64d\n", i, f.fib(i, fp)); // T(n) = O(n^2)
    }
    finish = clock();
    duration = (double)(finish - start) / CLOCKS_PER_SEC;
    printf(">>> Time: %2.3f seconds\n", duration);

    start = clock();
    printf ( "\n------------- Binary Recursion -------------\n" );
    for (int i = 0; i < n; i++)
    {
        printf("fib(%2d) = %22I64d\n", i, f.fib(i)); // T(n) = O(2^n)
    }
    finish = clock();
    duration = (double)(finish - start) / CLOCKS_PER_SEC;
    printf(">>> Time: %2.3f seconds\n", duration);

    return 0;
}

int main(int argc, char * argv[])
{
    std::cout << "\nReturn Value: " << mytest(argc, argv) << std::endl;

    system("pause");
    return 0;
}

/* End of mytest.cpp */

 

運行輸出:

------------- class Fib -------------
fib( 0) = 0
fib( 1) = 1
fib( 2) = 1
fib( 3) = 2
fib( 4) = 3
fib( 5) = 5
fib( 6) = 8
fib( 7) = 13
fib( 8) = 21
fib( 9) = 34
fib(10) = 55
fib(11) = 89
fib(12) = 144
fib(13) = 233
fib(14) = 377
fib(15) = 610
fib(16) = 987
fib(17) = 1597
fib(18) = 2584
fib(19) = 4181
fib(20) = 6765
fib(21) = 10946
fib(22) = 17711
fib(23) = 28657
fib(24) = 46368
fib(25) = 75025
fib(26) = 121393
fib(27) = 196418
fib(28) = 317811
fib(29) = 514229
fib(30) = 832040
fib(31) = 1346269
fib(32) = 2178309
fib(33) = 3524578
fib(34) = 5702887
fib(35) = 9227465
>>> Time: 0.000 seconds
fib(36) = 14930352
fib(35) = 9227465
fib(34) = 5702887
fib(33) = 3524578
fib(32) = 2178309
fib(31) = 1346269
fib(30) = 832040
fib(29) = 514229
fib(28) = 317811
fib(27) = 196418
fib(26) = 121393
fib(25) = 75025
fib(24) = 46368
fib(23) = 28657
fib(22) = 17711
fib(21) = 10946
fib(20) = 6765
fib(19) = 4181
fib(18) = 2584
fib(17) = 1597
fib(16) = 987
fib(15) = 610
fib(14) = 377
fib(13) = 233
fib(12) = 144
fib(11) = 89
fib(10) = 55
fib( 9) = 34
fib( 8) = 21
fib( 7) = 13
fib( 6) = 8
fib( 5) = 5
fib( 4) = 3
fib( 3) = 2
fib( 2) = 1
fib( 1) = 1
fib( 0) = 0
>>> Time: 0.000 seconds

------------- Iteration -------------
fib( 0) =                      0
fib( 1) =                      1
fib( 2) =                      1
fib( 3) =                      2
fib( 4) =                      3
fib( 5) =                      5
fib( 6) =                      8
fib( 7) =                     13
fib( 8) =                     21
fib( 9) =                     34
fib(10) =                     55
fib(11) =                     89
fib(12) =                    144
fib(13) =                    233
fib(14) =                    377
fib(15) =                    610
fib(16) =                    987
fib(17) =                   1597
fib(18) =                   2584
fib(19) =                   4181
fib(20) =                   6765
fib(21) =                  10946
fib(22) =                  17711
fib(23) =                  28657
fib(24) =                  46368
fib(25) =                  75025
fib(26) =                 121393
fib(27) =                 196418
fib(28) =                 317811
fib(29) =                 514229
fib(30) =                 832040
fib(31) =                1346269
fib(32) =                2178309
fib(33) =                3524578
fib(34) =                5702887
fib(35) =                9227465
>>> Time: 0.000 seconds

------------- Linear Recursion -------------
fib( 0) =                      0
fib( 1) =                      1
fib( 2) =                      1
fib( 3) =                      2
fib( 4) =                      3
fib( 5) =                      5
fib( 6) =                      8
fib( 7) =                     13
fib( 8) =                     21
fib( 9) =                     34
fib(10) =                     55
fib(11) =                     89
fib(12) =                    144
fib(13) =                    233
fib(14) =                    377
fib(15) =                    610
fib(16) =                    987
fib(17) =                   1597
fib(18) =                   2584
fib(19) =                   4181
fib(20) =                   6765
fib(21) =                  10946
fib(22) =                  17711
fib(23) =                  28657
fib(24) =                  46368
fib(25) =                  75025
fib(26) =                 121393
fib(27) =                 196418
fib(28) =                 317811
fib(29) =                 514229
fib(30) =                 832040
fib(31) =                1346269
fib(32) =                2178309
fib(33) =                3524578
fib(34) =                5702887
fib(35) =                9227465
>>> Time: 0.000 seconds

------------- Binary Recursion -------------
fib( 0) =                      0
fib( 1) =                      1
fib( 2) =                      1
fib( 3) =                      2
fib( 4) =                      3
fib( 5) =                      5
fib( 6) =                      8
fib( 7) =                     13
fib( 8) =                     21
fib( 9) =                     34
fib(10) =                     55
fib(11) =                     89
fib(12) =                    144
fib(13) =                    233
fib(14) =                    377
fib(15) =                    610
fib(16) =                    987
fib(17) =                   1597
fib(18) =                   2584
fib(19) =                   4181
fib(20) =                   6765
fib(21) =                  10946
fib(22) =                  17711
fib(23) =                  28657
fib(24) =                  46368
fib(25) =                  75025
fib(26) =                 121393
fib(27) =                 196418
fib(28) =                 317811
fib(29) =                 514229
fib(30) =                 832040
fib(31) =                1346269
fib(32) =                2178309
fib(33) =                3524578
fib(34) =                5702887
fib(35) =                9227465
>>> Time: 4.095 seconds

Return Value: 0
請按任意鍵繼續. . . 

 

--------------------------------------------------------------------------------

參考 http://blog.csdn.net/horizontalview/article/details/50804801

參考 http://www.cnblogs.com/joh-n-zhang/p/5759226.html

參考 http://blog.csdn.net/icaro_forever/article/details/46854857

相關文章
相關標籤/搜索