Coursera北大《資料結構基礎》之概論

愛看動漫的李皮皮發表於2018-10-31

刷書有點看不下去了,打算換課程試試。

Mooc上有一樣的內容,更喜歡Coursera。

 

本文基於Coursera北大課程《資料結構基礎》,所有文中非標註圖片均來自課件,侵刪


 

程式 = 資料結構 + 演算法

 

1. 問題求解

資料結構與演算法是圍繞問題求解進行的。那麼什麼是問題求解的過程呢?

我們要明確編寫計算機程式的目的是為了解決實際應用問題。面對一個問題,首先,我們要將其抽象出來,抓住問題的核心,建立問題模型;伴隨著問題會有一些資料出現,我們需要使用合適的資料結構來表示數學模型;在資料模型的基礎上,我們使用合理的演算法進行設計。

這裡要注意的一點是,資料結構是離不開演算法的,其由邏輯、儲存和運算三個方面組成。通常來說這裡的“運算”就是指演算法。通常程式設計中的演算法和資料結構抽象是可以一同進行的

課程中舉了一個《過河遊戲》的例子,剛好是我小時候很愛玩的一個遊戲(第二關怪獸吃人簡直是童年陰影),每一關都挺好玩的,值得嘗試,連結如下:

http://www.e-bobo.net/php/game1.php?ID=472&Page=6&Name=%E9%81%8E%E6%B2%B3%E9%81%8A%E6%88%B2

第一關如下:

狼不能和羊單獨在一起;羊不能和選單獨一起;人作為限制條件可以阻止A被B吃掉(人必須在船上)。目標是一頓操作要把狼羊菜都運到對岸。

這個問題中,模型就是人-狼-羊-菜的圖模型:

不合理狀態有:人狼、狼羊、羊菜、人菜、狼羊菜、人。

最終狀態為(右岸)空。

步驟如下:

我們可以把它轉化為一個矩陣求最短路徑的問題:

因為這個問題以後會詳細說,這裡就不展開了。

 

2. 資料結構與抽象資料型別

結構=實體+關係

資料結構=邏輯關係+資料儲存方法+運算【三者缺一不可】

整個資料結構以邏輯關係為主線來組織。

 

2.1 資料結構的邏輯關係

2.1.1 線性結構

線性表(表、棧、佇列、串等):最簡單最通用的結構

2.1.2 非線性結構

樹(二叉樹,Huffman樹,二叉檢索樹等)

圖(有向圖,無向圖等)

 

2.2 資料結構的儲存結構

是從邏輯結構到物理儲存空間的對映,主要有順序(陣列形式,連續儲存)、連結(指標的地址指向關係,十分重要,尤其對非線性結構)、索引(對資料建立索引表,通過表找到資料儲存地址)、雜湊(特殊的索引結構,通過關鍵碼對映快速找到儲存空間)四種形式組成,其中前兩種形式是基礎。

這裡注意一點,訪問記憶體任意一個地址所需要的時間都是相同的。

對於邏輯結構(K,r),其中r∈R,對結點集K建立一個從K到儲存器M的單元的對映:K→M,對於每一個結點j∈K都對應一個唯一的連續儲存區域c∈M。

具體例子如上圖所示,有一個長度為3的整型陣列a,如果a[0]的起始地址是4,那麼相對應地,a[1]就是8,a[2]是12(每一個整型數值佔4位元組)。

 

2.3 抽象資料型別(Abstract Data Type, ADT)

資料如何存放在記憶體裡並不是重點,重點是如何表示。抽象資料型別是隨著模組化物件導向方法發展起來的。

ADT主要關乎邏輯和運算兩個方面,和物理儲存沒有關係。

一個抽象資料結構二元組可以表達為:<資料物件D,資料操作P>

通常我們先定義邏輯結構(資料物件及其關係),再定義運算(資料操作)。

這裡舉了一個棧的ADT的例子:

棧的邏輯結構是線性表,操作特點是限制訪問埠,也就是說,棧必須是按照一定邏輯順序排列(如下圖所示)。棧遵循的是先進後出(出棧:讀pop;入棧:寫push),不允許從中間地址進行資料操作。

 

3. 演算法特性及分類

演算法是對特定問題求解過程的描述,是有限的指令。

3.1 演算法特性

(1)通用性

演算法對這一類問題都適用。例如求取1+2+3+4的和,我們可以用(1+4)*(4/2)=10求得,那麼推廣至:n個從a開始到b結束的整數的連加(n為偶數)則為(a+b)*(n/2)。

(2)有效性

演算法是有限條指令序列,由一系列具體步驟組成。每一步都必須是有效的。

(3)確定性

每一步都必須是明確的,可以獲得明確的結果,而不是模稜兩可的描述。

(4)有窮性

有限步數內結束。

 

3.2 演算法的分類

(1)窮舉法

就是挨個訪問、搜尋尋找答案

(2)回溯、搜尋

樹和圖遍歷。通過一些已知的不可能情況排除窮舉法中的一些例子,避免資源浪費

(3)遞迴分治

二分法、快排、歸併排序

(4)貪心法

前提是資料必須具有貪心特質,在每次一求解中都貪心最優解,得到的解的集合也是最優的。例如Huffman編碼樹、最短路徑Dijkstra演算法和最小生成樹Prim演算法等

(5)動態規劃

初高中學的那個

 

4. 演算法效率與度量

設計一個演算法後,我們要關注演算法的時間和空間效率,尤其是時間效率(即該演算法能不能在規定時間內完成任務)。

 

4.1 大O表式法(時間效率)

(1)定義

設f和g是定義域為自然數、值域為非負實數集的函式。如果存在正數c和n0,使得對於任意n>=n0,都有f(n)<=cg(n)【即f(n)總在集合O(g(n))中】,則稱f(n)是O(g(n))的,或f(n)=O(g(n))。

 

(2)相關符號

大O表示一個函式增長率的上限,這裡需要注意一個函式的增長率上限可能不止一個,我們需要儘量尋找最逼近的那個。

除了大O表式法,我們還用Ω來表示一個函式增長率的下限,有大Ω表式法。當同時表示上限和下限時,我們用Θ。在很多資料結構教材裡,人們會把ΩΘ混用。一般教材中只會介紹大O表式法,當遇到其它兩種時,用類比思想考慮即可【即找到最緊的下界用大Ω表式法;當上限和下限相同時,用大Θ表式法:有c1和c2把f夾在中間】。

 

(3)關於n<n0的部分

我們預設n0之前的n是小樣本的,因此並不關心n0之前的效率問題。

 

(4)大O表式法的單位時間

以下簡單的語句可以被視為單位時間:

  1. 簡單boolean或算術運算
  2. 簡單函式I/O(不包括耗時、不可控的外設I/O)
  3. 函式返回

 

(5)大O表式法運演算法則

加法規則:f_{1}(n)+f_{2}(n)=O(max(f_{1}(n)+f_{2}(n)))

例如

f(n)=n^{3}+log(n)+238

中,O(f(n))=n^3

加法規則在順序結構(如if, switch)中適用


乘法規則:f_{1}(n)\times f_{2}(n)=O(f_{1}(n)\times f_{2}(n))

適用於for, while, do-while結構

例如如下程式碼塊的大O複雜度就是n*n。

for(i=0;i<n;i++){
    for(j=0;j<n;j++){
    }    
}

 

4.2 增長率函式曲線

 

如圖所示【上圖摘自Coursera北京大學《資料結構與演算法》】,如果能找到log2n的增長率演算法就很好了。但是在做搜尋引擎等演算法時,我們希望O(f)=O(1)的,需要特殊的演算法。

 

通常在設計一個演算法時,我們需要考慮最好(例如排序中的插入排序)、最壞(壓力測試)和平均情況(統計意義下演算法大致效能,例如概率期望值),然後進行組合考慮。

 

4.3 二分法檢索效能分析

在決策樹下,每下降一層的效能都用log以2為底來衡量。

 

在上圖【摘自Coursera北京大學《資料結構與演算法》】的例子中,我們使用二分法檢索,用到了二叉樹。最大檢索長度為log2(n+1)

二分查詢的基本思想是將n個元素分成大致相等的兩部分,去a[n/2]與x做比較,如果x=a[n/2],則找到x,演算法中止;如果x<a[n/2],則只要在陣列a的左半部分繼續搜尋x,如果x>a[n/2],則只要在陣列a的右半部搜尋x.

時間複雜度無非就是while迴圈的次數!

總共有n個元素,

漸漸跟下去就是n,n/2,n/4,....n/2^k,其中k就是迴圈的次數

由於你n/2^k取整後>=1

即令n/2^k=1【二分只能到1,之後要結束】

可得k=log2n,(是以2為底,n的對數)

所以時間複雜度可以表示O()=O(logn)
--------------------- 
作者:frances_han 
來源:CSDN 
原文:https://blog.csdn.net/frances_han/article/details/6458067 
版權宣告:本文為博主原創文章,轉載請附上博文連結!

 

4.4 資料結構和演算法的選擇

大多數時候資料結構的設計是先於演算法設計的,但是也有特殊情況,例如某些經典問題需要特定演算法解決,我們可能為了能實現這種演算法而用特定資料結構來表示。

在設計資料結構時,要注意資料結構的可擴充套件性,即在資料輸入規模發生變化時,資料結構是否能夠適應並依然能夠進行問題求解。

相關文章