別找了 這就是適合入門的第一本算法書

《個人第一本算法書》根據 iOS 和 Android 平臺上的應用程序「算法動畫圖解」編寫而成,爲配合圖書出版,對內容進行了補充和修正,專門添加了基礎理論方面的內容。算法

決定了數據的順序和位置關係

數據存儲於計算機的內存中。內存如右圖所示,形似排成 1 列的箱子,1 個箱子裏存儲 1 個數據。數組

數據存儲於內存時,決定了數據順序和位置關係的即是「數據結構」。數據結構

圖像說明文字

電話簿的數據結構

▶ 例① 從上往下順序添加

舉個簡單的例子。假設咱們有 1 個電話簿——雖然說如今不少人都把電話號碼存在手機裏,可是這裏咱們考慮使用紙質電話簿的狀況——每當咱們獲得了新的電話號碼,就按從上往下的順序把它們記在電話簿上。學習

圖像說明文字

假設此時咱們想給「張偉」打電話,可是由於數據都是按獲取順序排列的,因此咱們並不知道張偉的號碼具體在哪裏,只能從頭一個個往下找(雖然說也能夠「從後往前找」或者「隨機查找」,可是效率並不會比「從上往下找」高)。若是電話簿上號碼很少的話很快就能找到,但若是存了 500 個號碼,找起來就不那麼容易了。動畫

▶ 例② 按姓名的拼音順序排列

接下來,試試以聯繫人姓名的拼音順序排列吧。由於數據都是以字典順序排列的,因此它們是有「結構」的。3d

圖像說明文字

使用這種方式給聯繫人排序的話,想要找到目標人物就輕鬆多了。經過姓名的拼音首字母就能推測出該數據的大體位置。指針

那麼,如何往這個按拼音順序排列的電話簿裏添加數據呢?假設咱們認識了新朋友「柯津博」並拿到了他的電話號碼,打算把號碼記到電話簿中。因爲數據按姓名的拼音順序排列,因此柯津博必須寫在韓宏宇和李希之間,可是上面的這張表裏已經沒有空位可供填寫,因此須要把李希及其如下的數據往下移 1 行。cdn

此時咱們須要從下往上執行「將本行的內容寫進下一行,而後清除本行內容」的操做。若是一共有 500 個數據,一次操做須要 10 秒,那麼 1 個小時也完成不了這項工做。blog

▶ 兩種方法的優缺點

總的來講,數據按獲取順序排列的話,雖然添加數據很是簡單,只須要把數據加在最後就能夠了,可是在查詢時較爲麻煩;以拼音順序來排列的話,雖然在查詢上較爲簡單,可是添加數據時又會比較麻煩。排序

雖然說這兩種方法各有各的優缺點,但具體選擇哪一種仍是要取決於這個電話簿的用法。若是電話簿作好以後就再也不添加新號碼,那麼選擇後者更爲合適;若是須要常常添加新號碼,但不怎麼須要再查詢,就應該選擇前者。

▶ 將獲取順序與拼音順序結合起來怎麼樣

咱們還能夠考慮一種新的排列方法,將兩者的優勢結合起來。那就是分別使用不一樣的表存儲不一樣的拼音首字母,好比表 L、表 M、表 N 等,而後將同一張表中的數據按獲取順序進行排列。

圖像說明文字 圖像說明文字

這樣一來,在添加新數據時,直接將數據加入到相應表中的末尾就能夠了,而查詢數據時,也只須要到其對應的表中去查找便可。

由於各個表中存儲的數據依舊是沒有規律的,因此查詢時仍需從表頭開始找起,但比查詢整個電話簿來講仍是要輕鬆多了。

選擇合適的數據結構以提升內存的利用率

數據結構方面的思路也和製做電話簿時的同樣。將數據存儲於內存時,根據使用目的選擇合適的數據結構,能夠提升內存的利用率。

本章將會講解 7 種數據結構。如本節開頭所述,數據在內存中是呈線性排列的,可是咱們也可使用指針等道具,構造出相似「樹形」的複雜結構(樹形結構將在 4-2 節詳細說明)。

參考:4-2 廣度優先搜索

1-2 鏈表

鏈表是數據結構之一,其中的數據呈線性排列。在鏈表中,數據的添加和刪除都較爲方便,就是訪問比較耗費時間。

圖像說明文字 圖像說明文字

解說

對鏈表的操做所需的運行時間究竟是多少呢?在這裏,咱們把鏈表中的數據量記成n。訪問數據時,咱們須要從鏈表頭部開始查找(線性查找),若是目標數據在鏈表最後的話,須要的時間就是 O(n)。

另外,添加數據只須要更改兩個指針的指向,因此耗費的時間與 n 無關。若是已經到達了添加數據的位置,那麼添加操做只需花費 O(1) 的時間。刪除數據一樣也只需O(1) 的時間。

參考:3-1 線性查找 

補充說明

上文中講述的鏈表是最基本的一種鏈表。除此以外,還存在幾種擴展方便的鏈表。

雖然上文中提到的鏈表在尾部沒有指針,但咱們也能夠在鏈表尾部使用指針,而且讓它指向鏈表頭部的數據,將鏈表變成環形。這即是「循環鏈表」,也叫「環形鏈表」。循環鏈表沒有頭和尾的概念。想要保存數量固定的最新數據時一般會使用這種鏈表。

圖像說明文字

另外,上文鏈表裏的每一個數據都只有一個指針,但咱們能夠把指針設定爲兩個,而且讓它們分別指向先後數據,這就是「雙向鏈表」。使用這種鏈表,不只能夠從前日後,還能夠從後往前遍歷數據,十分方便。

可是,雙向鏈表存在兩個缺點:一是指針數的增長會致使存儲空間需求增長;二是添加和刪除數據時須要改變動多指針的指向。

圖像說明文字

1-3 數組

數組也是數據呈線性排列的一種數據結構。與前一節中的鏈表不一樣,在數組中,訪問數據十分簡單,而添加和刪除數據比較耗工夫。這和 1-1 節中講到的姓名按拼音順序排列的電話簿相似。

參考:1-1 什麼是數據結構 

圖像說明文字 圖像說明文字 圖像說明文字 圖像說明文字

解說

這裏講解一下對數組操做所花費的運行時間。假設數組中有 n 個數據,因爲訪問數據時使用的是隨機訪問(經過下標可計算出內存地址),因此須要的運行時間僅爲恆定的O(1)。

但另外一方面,想要向數組中添加新數據時,必須把目標位置後面的數據一個個移開。因此,若是在數組頭部添加數據,就須要 O(n) 的時間。刪除操做同理。

補充說明

在鏈表和數組中,數據都是線性地排成一列。在鏈表中訪問數據較爲複雜,添加和刪除數據較爲簡單;而在數組中訪問數據比較簡單,添加和刪除數據卻比較複雜。

咱們能夠根據哪一種操做較爲頻繁來決定使用哪一種數據結構。

圖像說明文字

1-4棧

棧也是一種數據呈線性排列的數據結構,不過在這種結構中,咱們只能訪問最新添加的數據。棧就像是一摞書,拿到新書時咱們會把它放在書堆的最上面,取書時也只能從最上面的新書開始取。

圖像說明文字 圖像說明文字

解說

像棧這種最後添加的數據最早被取出,即「後進先出」的結構,咱們稱爲 Last In First Out,簡稱 LIFO。

與鏈表和數組同樣,棧的數據也是線性排列,但在棧中,添加和刪除數據的操做只能在一端進行,訪問數據也只能訪問到頂端的數據。想要訪問中間的數據時,就必須經過出棧操做將目標數據移到棧頂才行。

應用示例

棧只能在一端操做這一點看起來彷佛十分不便,但在只須要訪問最新數據時,使用它就比較方便了。

好比,規定(AB(C(DE)F)(G((H)I J)K))這一串字符中括號的處理方式以下:首先從左邊開始讀取字符,讀到左括號就將其入棧,讀到右括號就將棧頂的左括號出棧。此時,出棧的左括號便與當前讀取的右括號相匹配。經過這種處理方式,咱們就能得知配對括號的具體位置。

另外,咱們將要在 4-3 節中學習的深度優先搜索算法,一般會選擇最新的數據做爲候補頂點。在候補頂點的管理上就可使用棧。

參考:4-3 深度優先搜索

相關文章
相關標籤/搜索