算法基礎知識總結


1.基本概念

1.1 背景

1.2 術語

1.1.1 數據(Data)

分為數值型數據和非數值型數據

1.1.2 數據元素(Data Element)

數據的基本單位,在計算機程序中通常作為一個整體進行考慮和處理,也簡稱為元素,或稱為記錄結點頂點

1.1.3 數據項(Data Item)

構成數據元素的不可分割最小單位

1.1.4 數據對象(Data Object)

性質相同的數據元素的集合,是數據的一個子集

1.1.5 數據結構(Data Structure)

數據元素不是孤立存在的,它們之間存在着某種關系,數據元素相互之間的關系稱為結構(Structure)

是指相互之間存在一種或多種特定關系數據元素集合;或者說,數據結構是帶結構的數據元素的集合

數據結構包括以下三個方面的內容:

  1. 數據元素之間的邏輯關系,也稱為邏輯結構

  2. 數據元素及其關系在計算機內存中的表示(又稱為映像),稱為數據的物理結構或數據的存儲結構

  3. 數據的運算和實現,即對數據元素可以施加的操作以及這些操作在相應的存儲結構上的實現

1.1.5.1 數據結構的兩個層次

1.1.5.1.1 邏輯結構
  • 描述數據元素之間的邏輯關系

  • 與數據的存儲無關,獨立於計算機

  • 是從具體問題抽象出來的數學模型

1.1.5.1.1.1 邏輯結構的種類
划分方法一
  1. 線性結構

有且僅有一個開始和一個終端結點,並且所有結點都最多只有一個直接前趨和一個直接后繼

例如:線性表、棧、隊列、串

  1. 非線性結構

一個結點可能有多個直接前取和直接后繼

例如:樹、圖

划分方式二—四類基本邏輯結構
  1. 集合結構:結構中的數據元素之間除了同屬於一個集合的關系外,無任何其它關系

  2. 線性結構:結構中的數據元素之間存在着一對一的線性關系

  3. 樹形結構:結構中的數據元素之間存在着一對多的層次關系

1.1.5.1.2 物理結構(存儲結構)
  • 數據元素及其關系在計算機存儲器中的結構(存儲方式)

  • 是數據結構在計算機中的表示

四種基本的存儲結構
  • 順序存儲結構

用一組連續的存儲單元依次存儲數據元素,數據元素之間的邏輯關系由元素的存儲位置來表示

例如:C語言中用數組來實現順序存儲結構

  • 鏈式存儲結構

用一組任意的存儲單元存儲數據元素,數據元素之間的邏輯關系用指針來表示

例如:C語言中用指針來實現鏈式存儲結構

  • 索引存儲結構

在存儲結點信息的同時,還建立附加的索引表

索引表中的每一項稱為一個索引項

索引項的一般形式是:(關鍵字,地址)

關鍵字是能唯一標識一個結點的那些數據項

若每個結點在索引表中都有一個索引項,則該索引表稱為稠密索引(Dense Index)。若一組結點在索引表中只對應一個索引項,則該索引表稱之為稀疏索引(Sparse Index)

  • 散列存儲結構

根據結點的關鍵字直接計算出該結點的存儲地址

1.1.5.1.3 邏輯結構與存儲結構的關系
  • 存儲結構是邏輯關系的映像元素本身的映像

  • 邏輯結構是數據結構的抽象,存儲結構是數據結構的實現

1.1.6 數據類型和抽象數據類型

在使用高級程序設計語言編寫程序時,必須對程序中出現的每個變量、常量或表達式明確說明它們所屬的數據類型

高級語言中的數據類型明顯地或隱含地規定了在程序執行期間變量的所有可能的取值范圍,以及在這些數值范圍上所允許進行的操作

數據類型的作用:

  1. 約束變量或常量的取值范圍

  2. 約束變量或常量的操作

數據類型(Data Type)

定義:數據類型是一組性質相同的值的集合以及定義於這個值集合上的一組操作的總稱

數據類型 = 值的集合 + 值集合上的一組操作

抽象數據類型(Abstract Data Type, ADT)

定義:是指一個數學模型以及定義在此數學模型上的一組操作

  • 由用戶定義,從問題抽象出數據模型(邏輯結構)

  • 還包括定義在數學模型上的一組抽象運算(相關操作)

  • 不考慮計算機內的具體存儲結構與運算的具體實現算法

抽象數據類型的形式定義:

抽象數據類型可用(D, S, P)三元組表示。

其中:D是數據對象;S是D上的關系集;P是對D的基本操作集

一個抽象數據類型的定義格式如下:

ADT 抽象數據類型名{
    數據對象:<數據對象的定義>
    數據關系:<數據關系的定義>
    基本操作:<基本操作的定義>
} ADT 抽象數據類型名

其中:

  • 數據對象、數據關系的定義用偽代碼描述

  • 基本操作的定義格式為:

    • 基本操作名(參數表)

    • 初始條件:<初始條件描述>

    • 操作結果:<操作結果描述>

基本操作定義格式說明:

參數表:賦值參數只為操作提供輸入值。引用參數以&打頭,除可提供輸入值外,還將返回操作結果

初始條件:描述操作執行之前數據結構和參數應滿足的條件,若不滿足,則操作失敗,並返回相應出錯信息。若初始條件為空,則省略之

操作結果:說明操作正常完成之后,數據結構的變化狀況和應返回的結果。

e.g. Circle

ADT Circle{
    數據對象:D = {r,x,y|r,x,y均為實數}
    數據關系:S = {<r,x,y>|r是半徑,<x,y>是圓心坐標}
    基本操作:
    Circle(&C,r,x,y)
        操作結果:構造一個圓
    double Area(C)
        初始條件:圓已存在
        操作結果:計算面積
    double Circumference(C)
        初始條件:圓已存在
        操作結果:計算周長
    ......
} ADT Circle

e.g. 復數

ADT Complex{
    數據對象:D = {r1, r2|r1,r2都是實數}
    數據關系:S = {<r1, r2>|r1是實部,r2是虛部}
    基本操作:
    assign(&C,v1,v2)
        初始條件:空的復數C已存在
        操作結果:構造復數C,r1,r2分別被賦以參數v1,v2的值
    destory(&C)
        初始條件:復數C已存在
        操作結果:復數C被銷毀
    GetReal(C, &realPart)
        初始條件:復數C已存在
        操作結果:用realPart返回復數C的實部值
    GetImag(C, &ImagPart)
        初始條件:復數已存在
        操作結果:用ImagPart返回復數C的虛部值
    Add(c1, c2, &sum)
        初始條件:c1, c2是復數
        操作結果:sum返回兩個復數c1, c2的和
    ......
} ADT Complex

1.3 總結

2.抽象數據類型的表示與實現

抽象數據類型可以通過固有的數據類型(如整型、實型、字符型等)來表示和實現

  • 即利用處理器中已存在的數據類型來說明新的結構,用已經實現的操作來組合新的操作

例如:抽象數據類型“復數”的實現

typedef struct{
    float realpart; // 實部
    float imagpart; // 虛部
}Complex // 定義復數抽象類型

Complex assign(Complex* A, float real, float imag); // 賦值
Complex add(Complex* c, Complex A, Complex B); // A + B
Complex minus(Complex* c, Complex A, Complex B); // A - B
Complex multiply(Complex* c, Complex A, Complex B); // A * B
Complex divide(Complex* c, Complex A, Complex B); // A / B
Complex assign(Complex* A, float real, float imag){
    A->realpart = real; // 實部賦值
    A->imagpart = imag; // 虛部賦值
    return A;
}

Complex add(Complex* c, Complex A, Complex B){
    c->realpart = A.realpart + B.realpart; // 實部相加
    c->imagpart = A.imagpart + B.imagpart; // 虛部相加
    return c;
}

Complex minus(Complex* c, Complex A, Complex B){
    c->realpart = A.realpart - B.realpart; // 實部相減
    c->imagpart = A.imagpart - B.imagpart; // 虛部相減
    return c;
}

Complex multiply(Complex* c, Complex A, Complex B){
    c->realpart = A.realpart * B.realpart - A.imagpart * B.imagpart;
    c->imagpart = A.imagpart * B.realpart + A.realpart * B.imagpart;
    return c;
}

Complex divide(Complex* c, Complex A, Complex B){
    c->realpart = (A.realpart * B.realpart + A.imagpart * B.imagpart) / (B.realpart * B.realpart + B.imagpart * B.imagpart);
    c->imagpart = (A.imagpart * B.realpart - A.realpart * B.imagpart) / (B.realpart * B.realpart + B.imagpart * B.imagpart);
    return c;
}

3.算法和算法分析

算法的定義:對特定問題求解方法和步驟的一種描述,它是指令有限序列。其中每個指令表示一個或多個操作。簡言之,算法就是解決問題的方法和步驟

算法的描述:

  • 自然語言

  • 流程圖:傳統流程圖、NS流程圖

  • 偽代碼/類語言

  • 程序代碼

算法與程序

  • 算法是解決問題的一種方法或一個過程,考慮如何將輸入轉換成輸出,一個問題可以有多種算法

  • 程序是用某種程序設計語言對算法的具體實現

程序 = 數據結構 +算法

數據結構通過算法實現操作

算法根據數據結構設計程序

算法特性

一個算法必須具備以下五個重要特性:

  • 有窮性:一個算法必須總是在執行有窮步之后結束,且每一步都在有窮時間內完成

  • 確定性:算法中的每一條指令必須有確切的含義,沒有二義性,在任何條件下,只有唯一的一條執行路徑,即對於相同的輸入只能得到相同的輸出

  • 可行性:算法是可執行的,算法描述的操作可以通過已經實現的基本操作執行有限次來實現

  • 輸入:一個算法有零個或多個輸入

  • 輸出:一個算法有一個或多個輸出

算法設計的要求

  • 正確性(Correctness)

  • 可讀性(Readability)

  • 健壯性(Robustness)

  • 高效性(Efficiency)

一個好的算法首先要具備正確性,然后是健壯性,可讀性,在幾個方面都滿足的情況下,主要考慮算法的效率,通過算法的效率高低來評判不同算法的優劣程度

算法效率以下兩個方面來考慮:

  1. 時間效率:指的是算法所耗費的時間

  2. 空間效率:指的是算法執行過程中所耗費的存儲空間

注意:時間效率和空間效率往往不可兼得

算法時間效率的度量

算法時間效率可以用依據該算法編制的程序在計算機上執行所消耗的時間來度量

兩種度量方法:

  • 事后統計

    • 將算法實現,測算其時間和空間開銷

    • 缺點:編寫程序實現算法將花費較多的時間和精力;所得實驗結果依賴於計算機的軟硬件等環境因素,掩蓋算法本身的優劣

  • 事前分析

    • 對算法所消耗資源的一種估算方法

      • 一個算法的運行時間是指一個算法在計算機上運行所耗費的時間大致可以等於計算機執行一種簡單的操作(如賦值、比較、移動等)所需的時間與算法中進行的簡單操作次數乘積

        算法運行時間 = 一個簡單操作所需時間 x 簡單操作次數

      • 也即算法中每條語句的執行時間之和

      算法運行時間 = \(\sum\)每條語句的執行次數 x 該語句執行一次所需的時間

注意:每條語句的執行次數又稱為語句頻度

每條語句執行依次所需的時間,一般是隨機器而異的。取決於機器的指令性能、速度以及編譯的代碼質量。是由機器本身軟硬件環境決定的,它與算法無關

所以我們可以假設執行每條語句所需的時間均為單位時間。此時對算法的運行時間的討論就可轉化為討論該算法中所有語句的執行次數,即頻度之和

這就可以獨立於不同機器的軟硬件環境來分析算法的時間性能了

O:Order 數量級

一般情況下,不必計算所有操作的執行次數,而只考慮算法中基本操作執行的次數,它是問題規模n個某個函數,用T(n)表示

基本語句:

  • 算法中重復執行次數和算法的執行時間成正比的語句

  • 對算法運行時間的貢獻最大

  • 執行次數最多

問題規模n:n越大算法的執行時間越長

  • 排序:n為記錄數

  • 矩陣:n為矩陣的階數

  • 多項式:n為多項式的項數

  • 集合:n為元素個數

  • 樹:n為樹的結點個數

  • 圖:n為圖的頂點數或邊數

定理1.1

若f(n) = \(a_{m}n^{m}\)+\(a_{m-1}n^{m-1}\)+...+\(a_1n\)+\(a_0\)是m次多項式,則T(n) = O(\(n^{m}\))

忽略所有低次冪項和最高次冪系數,體現出增長率的含義

分析算法時間復雜度的基本方法

  1. 找出語句頻度最大的那條語句作為基本語句

  2. 計算基本語句的頻度得到問題規模n的某個函數f(n)

  3. 取其數量級用符號"O"表示

注意:時間復雜度是由嵌套最深層語句的頻度決定的

練習:

算法時間復雜度

請注意:有的情況下,算法中基本操作重復執行的次數還隨問題的輸入數據集不同而不同

[例] 順序查找,在數組中查找值等於e的元素,返回其所在位置

for(i = 0; i < n; i++)
    if(a[i] == e) return i + 1;
return 0;

最好情況:1次;最壞情況:n;平均時間復雜度為:O(n)

  • 最壞時間復雜度:指在最壞情況下,算法的時間復雜度

  • 平均時間復雜度:指在所有可能輸入實例在等概率出現的情況下,算法的期望運行時間

  • 最好時間復雜度:指在最好情況下,算法的時間復雜度

對於復雜的算法,可以將它分成幾個容易估算的部分,然后利用大O加法法則和乘法法則,計算算法的時間復雜度

  1. 加法法則:T(n) = \({T_1}\)(n) + \(T_2\)(n) = O(f(n)) + O(g(n)) = O(max(f(n),g(n)))

  2. 乘法法則:T(n) = \({T_1}\)(n) × \(T_2\)(n) = O(f(n)) × O(g(n)) = O(f(n)×g(n))

算法時間效率的比較

  • 當n取得很大時,指數時間算法和多項式時間算法在所需時間上非常懸殊

復雜度:O(1) < O(logn) < O(n) < O(nlogn) < O(\(n^{2}\)) < O(\(n^{3}\)) < ······ < O(\(n^{k}\)) < O(\(2^{n}\)) < O(n!)

漸進空間復雜度

空間復雜度:算法所需存儲空間的度量,記作:S(n) = O(f(n)),其中n為問題的規模(或大小)

算法要占據的空間

  • 算法本身要占據的空間,輸入/輸出,指令,常量,變量等

  • 算法要使用的輔助空間

例如:將一維數組a中的n個數逆序存放到原數組中

// 算法1
for(int i = 0; i < n / 2; i++){
    // t為輔助空間
    t = a[i];
    a[i] = a[n-i-1];
    a[n-i-1] = t;

    // S(n) = O(1) 原地工作
}

// 算法2
for(int i = 0; i < n; i++){
    b[i] = a[n-i-1];
}
for(int i = 0; i < n; i++){
    a[i] = b[i];
}

// S(n) = O(n)

4.總結


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM