Python的數據結構與算法 - 邱乘屹的個人技術博客

數據結構

數據結構是計算機存儲、組織數據的方式。
在現實世界中,不同數據元素之間不是獨立的,而是存在特定關係的,我們將這些關係稱爲結構。
同樣在計算機中,數據元素也不是孤立、雜亂無序的,而是具有內在聯繫的數據集合。

按照不同的角度,數據結構可分爲邏輯結構和物理結構。
其中邏輯結構是面向問題的,
而物理結構是面向計算機的,
它們的基本目標都是將數據及其邏輯關係存儲到計算機內存中。

邏輯結構

邏輯結構:是指數據對象中數據元素之間的相互關係。分爲四種:集合結構、線性結構、樹形結構和圖形結構。
在這裏插入圖片描述

物理結構

物理(存儲)結構:是指數據的邏輯結構在計算機中的存儲形式。數據的存儲結構應正確反映數據元素之間的邏輯關係,這是關鍵。

數據元素的存儲結構可分爲兩種:順序存儲結構 和 鏈式存儲結構。

順序存儲結構:
把數據元素放在地址連續的存儲單元中,數據間的邏輯關係和物理關係一致。如,數組。

鏈式存儲結構:把數據元素放在任意的存儲單元中,數據間使用指針關聯。
數據元素的存儲關係不能反映其邏輯關係。如,鏈表。

算法

算法是解決特定問題求解步驟的描述,在計算機中表現爲指令的有限序列,並且每條指令表示一個或多個操作。

算法的基本特性:

  1. 輸入,算法具有零個或多個輸入,
  2. 輸出,至少有一個或多個輸出。
  3. 有窮性,算法在執行有限步後能夠自動結束,不會出現無限循環。
  4. 確定性,算法的每一步都具有確定的含義,不會出現二義性。
  5. 可行性,算法的每一步都能夠通過執行有限次操作完成。

算法的複雜度

算法複雜度分爲時間複雜度和空間複雜度。

時間複雜度是指執行算法所需要的計算工作量(時間)

空間複雜度是指執行這個算法所需要的內存空間

時間複雜度

算法的時間複雜度反映了算法執行的時間長短,它是度量一個算法好壞的重要指標。
度量一個算法的時間複雜度通常採用“大O表示法”

時間複雜度的幾條基本計算規則:

  1. 基本操作,即只有常數項,認爲其時間複雜度爲O(1)
  2. 順序結構,時間複雜度按加法進行計算
  3. 循環結構,時間複雜度按乘法進行計算
  4. 分支結構,時間複雜度取最大值
  5. 判斷一個算法的效率時,往往只需要關注操作數量的最高次項,其它次要項和常數項可以忽略
  6. 在沒有特殊說明時,我們所分析的算法的時間複雜度都是指最壞時間複雜度
    在這裏插入圖片描述

list類型時間複雜度
在這裏插入圖片描述
dict類型時間複雜度
在這裏插入圖片描述
舉個例子:

for i in range(1): 
    print(i)                  # 時間複雜度是O(1)

for i in range(n): 
    print(i)                  # 時間複雜度是O(n)

for i in range(n): 
    for j in range(n):
        print(i,j)             # 時間複雜度是O(n2)

線性表

線性表是具有零個或多個數據元素的有限序列。線性表中數據元素之間的關係是一對一的關係,即除了第一個和最後一個數據元素之外,其它數據元素都是首尾相接的。

線性表的基本特徵:
第一個數據元素沒有前驅元素;
最後一個數據元素沒有後繼元素;
其餘每個數據元素只有一個前驅元素和一個後繼元素。

抽象數據類型:

線性表一般包括插入、刪除、查找等基本操作。

線性表按物理存儲結構的不同可分爲順序表(順序存儲)和鏈表(鏈式存儲):
順序表(存儲結構連續)
鏈表(存儲結構上不連續,邏輯上連續)

順序表

順序表是在計算機內存中以一組地址連續的存儲單元依次存儲數據元素的線性結構。
在這裏插入圖片描述
順序表效率分析:
順序表插入和刪除一個元素,最好情況下其時間複雜度(這個元素在最後一個位置)爲O(1),最壞情況下其時間複雜度爲O(n)。
順序表支持隨機訪問,讀取一個元素的時間複雜度爲O(1)。

順序表的優缺點:
優點:支持隨機訪問
缺點:插入和刪除操作需要移動大量的元素,造成存儲空間的碎片。

順序表適合元素個數變化不大,且更多是讀取數據的場合。Python中的list和tuple兩種類型採用了順序表的實現技術

鏈表

爲什麼需要鏈表?
順序表的構建需要預先知道數據大小來申請連續的存儲空間,而在進行擴充時又需要進行數據的搬遷,所以使用起來並不是很靈活。
鏈表結構可以充分利用計算機內存空間,實現靈活的內存動態管理。

那什麼是鏈表呢?
鏈表(Linked list)是一種常見的基礎數據結構,是一種線性表,但是不像順序表一樣連續存儲數據,而是在每一個節點(數據存儲單元)裏存放下一個節點的位置信息(即地址)。

鏈表可分爲單向鏈表、單向循環鏈表和雙向鏈表

在這裏插入圖片描述

這裏分別做解釋:

單向鏈表

單向鏈表也叫單鏈表,是鏈表中最簡單的一種形式,它的每個節點包含兩個域,一個信息域(元素域)和一個鏈接域。這個鏈接指向鏈表中的下一個節點,而最後一個節點的鏈接域則指向一個空值。
在這裏插入圖片描述

單向循環鏈表

單鏈表的一個變形是單向循環鏈表,鏈表中最後一個節點的next域不再爲None,而是指向鏈表的頭節點。
在這裏插入圖片描述

雙向鏈表

一種更復雜的鏈表是“雙向鏈表”或“雙面鏈表”。每個節點有兩個鏈接:一個指向前一個節點,當此節點爲第一個節點時,指向空值;而另一個指向下一個節點,當此節點爲最後一個節點時,指向空值。

鏈表與順序表的對比

鏈表失去了順序表隨機讀取的優點,同時鏈表由於增加了結點的指針域,空間開銷比較大,但對存儲空間的使用要相對靈活。
鏈表與順序表的各種操作複雜度如下所示:

在這裏插入圖片描述

注意雖然“在中間插入/刪除”表面看起來複雜度都是 O(n),但是鏈表和順序表在插入和刪除時進行的是完全不同的操作。鏈表的主要耗時操作是遍歷查找,刪除和插入操作本身的複雜度是O(1)。順序表查找很快,主要耗時的操作是拷貝覆蓋。因爲除了目標元素在尾部的特殊情況,順序表進行插入和刪除時需要對操作點之後的所有元素進行前後移位操作,只能通過拷貝和覆蓋的方法進行。

棧與隊列

棧(也稱下壓棧,堆棧)是僅允許在表尾進行插入和刪除操作的線性表。

我們把允許插入和刪除的一端稱爲棧頂(top),另一端稱爲棧底(bottom)。

棧是一種後進先出(Last In First Out)的線性表,簡稱(LIFO)結構。
在這裏插入圖片描述
具體代碼操作
Stack() 創建一個新的空棧
push(item) 添加一個新的元素item到棧頂
pop() 彈出棧頂元素
peek() 返回棧頂元素
is_empty() 判斷棧是否爲空
size() 返回棧的元素個數

隊列

隊列(queue)是隻允許在一端進行插入操作,而在另一端進行刪除操作的線性表。
在這裏插入圖片描述
具體代碼操作
Queue() 創建一個空的隊列
enqueue(item) 往隊列中添加一個item元素
dequeue() 從隊列頭部刪除一個元素
is_empty() 判斷一個隊列是否爲空
size() 返回隊列的大小

棧和隊列的區別

棧與隊列,它們都是特殊的線性表,只是對插入和刪除操作做了限制。

棧限定僅能在棧頂進行插入和刪除操作,而隊列限定只能在隊尾插入,在隊頭刪除。
棧:後進先出

隊列(queue)是隻允許在一端進行插入操作,而在另一端進行刪除操作的線性表。
隊列:先進先出

它們都可以使用順序存儲結構和鏈式存儲結構兩種方式來實現。

樹(英語:tree)是一種抽象數據類型(ADT)或是實作這種抽象數據類型的數據結構,用來模擬具有樹狀結構性質的數據集合。它是由n(n>=1)個有限節點組成一個具有層次關係的集合。把它叫做“樹”是因爲它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。
它具有以下的特點:
每個節點有零個或多個子節點;
沒有父節點的節點稱爲根節點;
每一個非根節點有且只有一個父節點;
除了根節點外,每個子節點可以分爲多個不相交的子樹;

術語

節點的度:一個節點含有的子樹的個數稱爲該節點的度;
樹的度:一棵樹中,最大的節點的度稱爲樹的度;
葉節點或終端節點:度爲零的節點;
父親節點或父節點:若一個節點含有子節點,則這個節點稱爲其子節點的父節點;
孩子節點或子節點:一個節點含有的子樹的節點稱爲該節點的子節點;
兄弟節點:具有相同父節點的節點互稱爲兄弟節點;
節點的層次:從根開始定義起,根爲第1層,根的子節點爲第2層,以此類推;
樹的高度或深度:樹中節點的最大層次;
堂兄弟節點:父節點在同一層的節點互爲堂兄弟;
節點的祖先:從根到該節點所經分支上的所有節點;
子孫:以某節點爲根的子樹中任一節點都稱爲該節點的子孫。
森林:由m(m>0)棵互不相交的樹的集合稱爲森林;

種類

無序樹:樹中任意節點的子節點之間沒有順序關係,這種樹稱爲無序樹,也稱爲自由樹;
有序樹:樹中任意節點的子節點之間有順序關係,這種樹稱爲有序樹;
二叉樹:每個節點最多含有兩個子樹的樹稱爲二叉樹;
完全二叉樹:對於一顆二叉樹,假設其深度爲d(d>1)。除了第d層外,其它各層的節點數目均已達最大值,且第d層所有節點從左向右連續地緊密排列,這樣的二叉樹被稱爲完全二叉樹,其中滿二叉樹的定義是所有葉節點都在最底層的完全二叉樹;
平衡二叉樹(AVL樹):當且僅當任何節點的兩棵子樹的高度差不大於1的二叉樹;
排序二叉樹(二叉查找樹(英語:Binary Search Tree),也稱二叉搜索樹、有序二叉樹);
霍夫曼樹(用於信息編碼):帶權路徑最短的二叉樹稱爲霍夫曼樹或最優二叉樹;
B樹:一種對讀寫操作進行優化的自平衡的二叉查找樹,能夠保持數據有序,擁有多餘兩個子樹。

應用場景

  1. xml,html等,編寫這些東西的解析器的時候,不可避免用到樹
  2. 路由協議就是使用了樹的算法
  3. mysql數據庫索引(B+樹)
  4. 文件系統的目錄結構
  5. 很多經典的AI算法其實都是樹搜索
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章