基礎數據結構和算法概念

本文涉及更多的是概念,代碼部分請參考以前寫過的 2 篇博客前端

排序算法 基於Javascript
基本數據結構和查找算法web

本文主要是基礎的數據結構和算法概念,可能部分地方會涉及更高級的算法和算法,具體內容之後會單獨寫的。此外一些性質還會不斷補充,也但願能夠獲得您的指點,謝謝。算法

數據結構

程序 = 數據結構 + 算法數組

數據結構基本概念

  1. 數據的邏輯結構:反映數據元素之間的關係的數據元素集合的表示。數據的邏輯結構包括集合、線形結構、樹形結構和圖形結構四種。
  2. 數據的存儲結構:數據的邏輯結構在計算機存儲空間種的存放形式稱爲數據的存儲結構。經常使用的存儲結構有順序、連接、索引等存儲結構。

在數據結構中,沒有前件的結點稱爲根結點,沒有後件的結點成爲終端結點markdown

數據結構的基本操做數據結構

插入和刪除是對數據結構的兩種基本操做。此外還有查找、分類、合併、分解、複製和修改等。數據結構和算法

線性結構和非線性結構svg

根據數據結構中各數據元素之間先後件關係的複雜程度,通常將數據結構分爲兩大類型:線性結構和非線性結構。函數

  • 線性結構:有且只有一個根結點;每一個結點最多有一個前件,最多隻有一個後件。
  • 非線性結構: 若是一個數據結構不是線性結構,稱之爲非線性結構。

本文涉及一下內容:atom

  • 四種線性結構的存儲結構:順序表、鏈表、索引、散列
  • 兩種常見的線性邏輯結構:隊列、棧
  • 非線性邏輯結構:循環隊列、雙向隊列、雙向循環隊列、樹、圖

存儲結構

順序表

順序表是線性表的順序存儲結構,指的是用一組地址連續的存儲單元依次存儲線性表的數據元素。
順序表具有以下兩個基本特徵:

  1. 順序表中的全部元素所佔的存儲空間是連續的;
  2. 順序表中各數據元素在存儲空間中是按邏輯順序依次存放的。

假設順序表的每一個元素需佔用 K 個存儲單元,並以所佔的第一個單元的存儲地址做爲數據元素的存儲位置。則順序表中第 i + 1 個數據元素的存儲位置 L O C ( a i + 1 ) 和第 i 個數據元素的存儲位置 L O C ( a i ) 之間知足下列關係爲:

L O C ( a i + 1 ) = L O C ( a i ) + K

L O C ( a i ) = L O C ( a 1 ) + ( i 1 ) K

其中, L O C ( a 1 ) 是順序表的第一個數據元素 a 1 的存儲位置,一般稱作順序表的起始位置或基地址。順序存儲結構也稱隨機存取結構。

順序表常見操做(括號中爲算法平均時間複雜度,沒有寫明的具體複雜度依賴不一樣算法和運算規則):

插入( O ( n ) )、刪除( O ( n ) )、查找、排序、分解、合併、複製( O ( n ) )、逆轉( O ( n ) )

鏈表

鏈表指線性表的鏈式存儲結構。一組任意的存儲單元存儲線性表的數據元素,所以,爲了表示每一個數據元素 a i 與其直接後繼數據元素 a i + 1 之間的邏輯關係,對數據元素 a i 來講,除了存儲其自己的信息(數據域)以外,還需存儲一個變量指示其直接後繼的信息(指針域)。這兩部分信息組成數據元素 a i 的存儲映象,稱爲結點。 N 個結點鏈結成一個鏈表。該鏈表就是傳統的單向鏈表。

有時,咱們在單鏈表的第一個結點以前附設一個結點,稱之爲頭結點,它指向表中第一個結點。頭結點的數據域可 以不存儲任何信息,也可存儲如線性表的長度等類的附加信息,頭結點的指針域存儲指向第一個結點的指針。在單鏈表中,取得第 I 個數據元素必須從頭指針出發尋找,所以,鏈表是非隨機存取的存儲結構。

以上提到的鏈表指針域只包括一個指針,指向下一個數據的地址,若是咱們將鏈表最後一個結點指針域的指針指向鏈表的頭結點地址,就構成了一個環狀的存儲結構,咱們稱做循環鏈表。

固然咱們能夠給每一個結點的指針域再添加一個指針,使其指向前一個數據結點的地址,這樣就構成了雙向鏈表,而將頭結點的前一個結點指向尾結點,同時將尾結點的下一個結點指向頭結點就構成了雙向循環鏈表。

若是鏈表的尾結點的指針域指向了該鏈表以前的任意一個結點,咱們稱該鏈表爲有環鏈表。環形鏈表就是其中一個特例

順序表常見操做(括號中爲算法平均時間複雜度,沒有寫明的具體複雜度依賴不一樣算法和運算規則):

插入( O ( n ) )、刪除( O ( n ) )、查找、排序、分解、合併、複製( O ( n ) )、逆轉( O ( n ) )

索引

索引存儲除創建存儲結點信息外,還創建附加的索引表來標識結點的地址。索引表由若干索引項組成。

對於索引的理解最好的例子就是《新華字典》,它創建的2套索引表(拼音、部首)。字典的正文就是從「啊」到「作」的每一個字的解釋,有上千頁,就是是數據。而前面的拼音/部首就是索引表,索引表告訴你某個讀音/部首在第幾頁,這就比如是指向數據地址的指針。而索引表能夠有一級的也能夠是多級的,好比字典中的部首索引就是兩級的。

索引存儲結構是用結點的索引號來肯定結點存儲地址,其優勢是檢索速度快,缺點是增長了附加的索引表,會佔用較多的存儲空間。

散列

散列存儲,又稱哈希(hash)存儲,是一種力圖將數據元素的存儲位置(預留連續存儲區域)與關鍵碼之間創建肯定對應關係的查找技術。散列法存儲的基本思想是由結點的關鍵碼值決定結點的存儲地址。散列技術除了能夠用於存儲外,還能夠用於查找。

散列以數據中每一個元素的關鍵字 K 爲自變量,經過散列函數 H ( k ) 計算出函數值,以該函數值做爲一塊連續存儲空間的的單元地址,將該元素存儲到函數值對應的單元中。因爲該函數值惟一,因此查找時間複雜度爲 O ( 1 )

線性邏輯結構

線性表

線性表知足如下特徵:

  1. 有且只有一個根結點 a 1 ,它無前件;
  2. 有且只有一個終端結點 a n ,它無後件;
  3. 除根結點與終端結點外,其餘全部結點有且只有一個前件,也有且只有一個後件。線性表中結點的個數 n 稱 爲線性表的長度。當 n = 0 時稱爲空表。

棧實際上也是一個線性表,只不過是一種特殊的線性表。棧是隻能在表的一端進行插入和刪除運算的線性表,一般稱插入、刪除這一端爲棧頂(TOP),另外一端爲棧底(BOTTOM)。當表中沒有元素時稱爲棧空。 棧頂元素老是後被插入(入棧)的元素,從而也是最早被移除(出棧)的元素;棧底元素老是最早被插入的元素,從而也是最後才能被移除的元素。因此棧是個 後進先出(LIFO) 的數據結構

棧的基本運算有三種:入棧、出棧與讀棧頂,時間複雜度都是 O ( 1 )

隊列

隊列是隻容許在一端刪除,在另外一端插入的順序表,容許刪除的一端叫作隊頭,用對頭指針 f r o n t 指向對頭元素的下一個元素,容許插入的一端叫作隊尾,用隊尾指針 r e a r 指向隊列中的隊尾元素,所以,從排頭指針 f r o n t 指向的下一個位置直到隊尾指針 r e a r 指向的位置之間全部的元素均爲隊列中的元素。

隊列的修改是 先進先出(FIFO) 。往隊尾插入一個元素稱爲入隊運算。從對頭刪除一個元素稱爲退隊運算。

隊列主要有兩種基本運算:入隊運算和退隊運算,複雜度都是 O ( 1 )

循環隊列

在實際應用中,隊列的順序存儲結構通常採用循環隊列的形式。所謂循環隊列,就是將隊列存儲空間的最後一個 位置繞到第一個位置,造成邏輯上的環狀空間。在實際使用循環隊列時,爲了能區分隊滿仍是隊列空,一般須要增長一個標誌 S

循環隊列主要有兩種基本運算:入隊運算和退隊運算,複雜度都是 O ( 1 )

  • 入隊運算
    指在循環隊列的隊尾加入一個新元素,首先 r e a r = r e a r + 1 , 當 r e a r = m + 1 時,置 r e a r = 1 ,而後將新元素插入到隊尾指針 指向的位置。當 S = 1 , r e a r = f r o n t ,說明隊列已滿,不能進行入隊運算,稱爲「上溢」。
  • 退隊運算
    指在循環隊列的排頭位置退出一個元素並賦給指定的變量。首先 f r o n t = f r o n t + 1 , 並當 f r o n t = m + 1 時,置 f r o n t = 1 , 而後 將排頭指針指向的元素賦給指定的變量。當循環隊列爲空 S = 0 ,不能進行退隊運算,這種狀況成爲「下溢」。

非線性邏輯結構

樹是一種簡單的非線性結構。樹型結構具備如下特色:

  1. 每一個結點只有一個前件,稱爲父結點,沒有前件的結點只有一個,稱爲樹的根結點。
  2. 每個結點能夠有多個後件結點,稱爲該結點的子結點。沒有後件的結點稱爲葉子結點
  3. 一個結點所擁有的後件個數稱爲結點的度
  4. 樹的最大層次稱爲樹的深度。

二叉樹

二叉樹是一種樹型結構,一般採用鏈式存儲結構,知足如下特性:

  1. 它的特色是每一個結點至多隻有二棵子樹(即二叉樹中不存在度大於 2 的結點);
  2. 二叉樹的子樹有左右之分,其次序不能任意顛倒。

二叉樹的基本性質

  • 在二叉樹的第 i 層上至多有 2 i 1 個結點
  • 深度爲 k 的二叉樹至多有 2 k 1 個結點( k 1 )
  • 在任意一個二叉樹中,度爲 0 的結點老是比度爲 2 的結點多一個
  • 具備 N 個結點的二叉樹,其深度至少爲 l o g 2 N + 1
  • 霍夫曼樹的帶權路徑長度 l e n = 2 n + 1 ; n 爲因此葉子權重和。

二叉樹的遍歷

就是聽從某種次序,訪問二叉樹中的全部結點,使得每一個結點僅被訪問一次。分爲如下幾種:

  1. 前序遍歷(DLR): 首先訪問根結點,而後遍歷左子樹,最後遍歷右子樹。
  2. 中序遍歷(LDR): 首先遍歷左子樹,而後根結點,最後右子樹
  3. 後序遍歷(LRD): 首先遍歷左子樹,而後遍歷右子樹,最後訪問根結點。

此外圖的遍歷也能夠用在樹上,包括:

  1. 廣度優先遍歷(層序遍歷): 從根結點開開始逐層向下,從左到右遍歷。
  2. 深度優先遍歷: 從根結點出發沿左子樹遍歷到葉子結點再逐層向上向遍歷右子樹。

除此以外還有不少有特色的特殊二叉樹:

  • 滿二叉樹:除最後一層之外,每一層上的全部結點都有兩個子結點。
    1. 在滿二叉樹的第 K 層上有 2 K 1 個結點,且深度爲 M 的滿二叉樹有 2 M 1 個結點
    2. 徹底二叉樹:除最後一層之外,每一層上的結點數均達到最大值;在最後一層上只缺乏右邊的若干結點。
    3. 具備 N 個結點的徹底二叉樹的深度爲 l o g 2 N + 1
    4. 徹底二叉樹總結點數爲 N ,則葉子結點數爲 N / 2

最多見的徹底二叉樹就是 了。堆知足如下條件

  • 堆中某個結點的值老是不大於或不小於其父結點的值
  • 堆老是一棵徹底二叉樹

將根結點最大的堆叫作 最大堆大根堆 ,根結點最小的堆叫作 最小堆小根堆

堆具備如下基本操做:

  • 插入: 向堆中插入一個新元素
  • 獲取: 獲取當前堆頂元素的值
  • 刪除: 刪除堆頂元素
  • 包含: 判斷堆中是否存在某個元素

哈希表

經常使用的哈希函數

  1. 直接尋址法: H ( k ) 是一個線性函數,若是該位置已經有值就向下尋找到第一個空的地方做爲散列地址
  2. 平方取中法: 取 k 平方之後值的中間幾位做爲散列地址
  3. 數字分析法: 對於比較規律的 k 值,找出其差別較大的部分做爲散列地址
  4. 摺疊法: 將 k 分紅不少部分,而後作模二和做爲散列地址
  5. 留餘數法: H ( k ) = k ,其中 p 爲素數, m 爲表的長度
  6. 隨機數法: 取鍵字的隨機值做爲散列地址,關鍵字長度時使用

實現映射的函數是哈希函數,簡單的 hash 可能會發生碰撞(不一樣輸入獲得相同輸出),爲了防止碰撞,考慮如下方法:

  • 鏈地址法(拉鍊法): 當發生碰撞時,將發生碰撞的數據元素鏈接到同一個單鏈表中,而新元素插入到鏈表的前端
  • 線性探針法: 線性探針法地址增量 d D 1 = { 1 , 2 , 3 , . . . , m 1 } , i 爲探測次數, m 爲表的長度,該方法遇到衝突地址會依次探測下一個地址( d = d i + 1 )直到有空的地址,若找不到空地址,則溢出。

平均查找長度

  • 線性探針法平均長度推算(其中 m 爲表中數據長度, n 爲表長度):


    A S L s = i = 1 m d i m ,查找成功

    A S L u = i = 1 n d i n ,查找不成功


注:線性探針法查找成功時 d i 爲每次放入元素時的地址增量,不成功時 d i 爲在表長度內依次查找每一個元素到下一個空地址的地址增量(索引在表長度內循環)
  • 鏈地址法平均長度推算(其中 k 爲最長鏈長度,其中 m 爲表中數據長度, n 爲表長度):


    A S L s = i = 1 k ( × ) m ,查找成功

    A S L u = i = 1 n n ,查找不成功


哈希表相關特性
  • 線性探針法容易「彙集」,影響查找效率,而鏈地址法不會
  • 鏈地址法適應表長不肯定狀況
  • ( α ) =

圖有兩種定義:

  • 二元組的定義:圖 G 是一個有序二元組 ( V , E ) ,其中 V 稱爲頂集(Vertices Set), E 稱爲邊集(Edges set), E V 不相交。它們亦可寫成 V ( G ) E ( G ) E 的元素都是二元組,用 ( x , y ) 表示,其中 x , y V
  • 三元組的定義: 圖 G 是指一個三元組 ( V , E , I ) ,其中 V 稱爲頂集, E 稱爲邊集, E V 不相交; I 稱爲關聯函數, I E 中的每個元素映射到 V × V 。若是 e 被映射到 ( u , v ) ,那麼稱邊 e 鏈接頂點 u , v ,而 u , v 則稱做 e 的端點, u , v 此時關於 e 相鄰。同時,若兩條邊 i , j 有一個公共頂點 u ,則稱 i , j 關於 u 相鄰。

圖的分類

圖有不一樣的分類規則,具體以下:

分類1
- 有向圖: 若是圖中頂點之間關係不只僅是連通與不連通,並且區分兩邊的頂點的出入(存在出邊和入邊),則爲有向圖。
- 無向圖: 若是圖中頂點之間關係僅僅是連通與不連通,而不區分兩邊頂點的出入(不存在出邊和入邊),則爲無向圖。
單圖

分類2
- 有環圖: 單向遍歷回能夠到已遍歷的點,好比有環鏈表
- 無環圖: 單向遍歷不能回到已遍歷的點,好比樹

分類3
- 帶權圖: 圖的具備邊帶有關於該邊信息的權值,好比地圖中兩點間距離
- 無權圖: 圖的每一個邊都不具備有關於該邊信息的權值,其僅表示是否連通

其餘
- 單圖: 一個圖若是任意兩頂點之間只有一條邊且邊集中不含環,則稱爲單圖

圖的表示採用鄰接矩陣和相似樹的形式(頂點指針域是個指針數組)的形式,其具備如下特色:

  • 無向圖的鄰接矩陣是對稱矩陣
  • 帶權圖的矩陣中元素爲全職,無權圖中用0/1分別表示不連通/連通
  • 主對角線有不爲零元素,該圖必定有環

圖的遍歷

  • 廣度優先遍歷: 廣度優先遍歷是連通圖的一種遍歷策略。由於它的思想是從一個頂點 V 0 開始,輻射狀地優先遍歷其周圍較廣的區域。
  • 深度優先遍歷:

圖的相關性質:

  • N 個頂點的連通圖中邊的條數至少爲 N 1
  • N 個頂點的強連通圖的邊數至少有 N
  • 廣度優先遍歷用來找無權圖最短路徑(有權圖其實也行,多點東西唄)

簡單數據結構的增刪改查

操做 添加 刪除 查找 使用條件
數組 O ( n ) O ( n ) O ( n ) 數定下標
鏈表 O ( 1 ) O ( n ) O ( n ) 兩端修改
變長數組 O ( 1 ) O ( n ) O ( n ) 數不定下標
O ( 1 ) O ( 1 ) - LIFO
隊列 O ( 1 ) O ( 1 ) - FIFO
哈希表 O ( 1 ) O ( 1 ) O ( 1 ) key操做,無序
樹字典 O ( l o g 2 n ) O ( l o g 2 n ) O ( l o g 2 n ) key操做,有序
哈希集合 O ( 1 ) O ( 1 ) O ( 1 ) 惟一值,無序
樹集合 O ( l o g 2 n ) O ( l o g 2 n ) O ( l o g 2 n ) 惟一值,有序

算法

算法基本概念

  1. 算法的基本特徵:可行性,肯定性,有窮性
  2. 算法的基本要素:算法中對數據的運算和操做、算法的控制結構。
  3. 算法設計的基本方法:窮舉法、動態規劃、貪心法、回溯法、遞推法、遞歸法、分治法、散列法,分支限界法。
  4. 算法設計的要求:正確性、可讀性、健壯性、效率與低存儲量需求
  5. 算法的基本結構:順序、循環、選擇

算法複雜度

  1. 算法的時間複雜度:指執行算法所須要的計算工做量(不表明算法實際須要時間)
  2. 算法的空間複雜度:執行這個算法所須要的額外內存空間(表明算法實際須要的空間)

複雜度表示方法: 使用大寫 O 表示: O ( n ) 表示時間複雜度時指 n 個數據處理完成使用 n 個單位的時間;表示空間複雜度時指 n 個數據處理完成使用了 n 個單位的輔助空間。

字符串算法

字符串算法除了增刪改查之外,還有不少匹配算法,好比最耳熟能詳的 KMP 算法(不屬於基礎部分),這裏整理一些相關算法的性質:

  • 一個長爲 n 的字符串有 n ( n + 1 ) / 2 + 1 個子串
  • n的字符串,其中的字符各不相同,則S中的互異的非平凡子串有 1 2 n 2 + 1 2 n 1

排序算法

排序算法實際上能夠分爲內排序和外排序:

  • 內排序:在排序過程當中,全部元素調到內存中進行的排序,稱爲內排序。內排序是排序的基礎。內排序效率用比較次數來衡量。按所用策略不一樣,內排序又可分爲插入排序、選擇排序、堆排序、歸併排序、冒泡排序、快速排序、希爾排序及基數排序等等。
  • 外排序:在數據量大的狀況下,只能分塊排序,但塊與塊間不能保證有序。外排序用讀/寫外存的次數來衡量其效率。

排序算法時間複雜度

排序算法分爲如下幾類:

  1. 插入類排序:插入排序、希爾排序
  2. 交換類排序:冒泡排序、快速排序
  3. 選擇類排序:選擇排序、堆排序
  4. 歸併排序
  5. 基數排序
算法 時間複雜度(最好) 時間複雜度(最好) 時間複雜度(最壞) 空間複雜度 穩定性
插入排序 O ( n 2 ) O ( n ) O ( n 2 ) O ( 1 ) 穩定
希爾排序 O ( n 1.3 ) O ( n ) O ( n 2 ) O ( 1 ) 不穩定
選擇排序 O ( n 2 ) O ( n 2 ) O ( n 2 ) O ( 1 ) 不穩定
堆排序 O ( n l o g 2 n ) O ( n l o g 2 n ) O ( n l o g 2 n ) O ( 1 ) 不穩定
冒泡排序 O ( n 2 ) O ( n ) O ( n 2 ) O ( 1 ) 穩定
快速排序 O ( n l o g 2 n ) O ( n l o g 2 n ) O ( n 2 ) O ( n l o g 2 n ) 不穩定
歸併排序 O ( n l o g 2 n ) O ( n l o g 2 n ) O ( n l o g 2 n ) O ( n ) 穩定
基數排序 O ( d ( r + n ) ) O ( d ( n + r d ) ) O ( d ( r + n ) ) O ( n + r d ) 穩定

注:
1. 基數排序的複雜度中, r 表明關鍵字基數, d 表明長度, n 表明關鍵字個數
2. 排序算法的穩定性指在原序列中, r i = r j ,且 r i r j 以前,而在排序後的序列中, r i 仍在 r j 以前,則稱這種排序算法是穩定的;不然稱爲不穩定的。

查找算法

查找算法時間複雜度

算法 查找(最壞) 插入(最壞) 刪除(最壞) 查找(最好) 插入(最好) 刪除(最好) 是否要求有序
順序結構 N N N N 2 N N 2 No
二分算法 logN N N logN N 2 N 2 Yes
二叉查找樹(BST) N N N 1.39logN 1.39logN N Yes
2-3樹 clogN clogN clogN clogN clogN clogN Yes
紅黑樹 2logN 2logN 2logN logN logN logN Yes
哈希散列查找 logN logN logN 3~5 3~5 3~5 No
哈希探針查找 logN logN logN 3~5 3~5 3~5 No

平均查找長度(ASL) = 查找表中第 i 個元素機率( P i ) × 找到第 i 個元素時已經比較的次數( C i )

相關文章
相關標籤/搜索