基礎資料結構和演算法概念
本文涉及更多的是概念,程式碼部分請參考之前寫過的 2 篇部落格
本文主要是基礎的資料結構和演算法概念,可能部分地方會涉及更高階的演算法和演算法,具體內容以後會單獨寫的。此外一些性質還會不斷補充,也希望可以得到您的指點,謝謝。
資料結構
程式 = 資料結構 + 演算法
資料結構基本概念
- 資料的邏輯結構:反映資料元素之間的關係的資料元素集合的表示。資料的邏輯結構包括集合、線形結構、樹形結構和圖形結構四種。
- 資料的儲存結構:資料的邏輯結構在計算機儲存空間種的存放形式稱為資料的儲存結構。常用的儲存結構有順序、連結、索引等儲存結構。
在資料結構中,沒有前件的結點稱為根結點,沒有後件的結點成為終端結點
資料結構的基本操作
插入和刪除是對資料結構的兩種基本操作。此外還有查詢、分類、合併、分解、複製和修改等。
線性結構和非線性結構
根據資料結構中各資料元素之間前後件關係的複雜程度,一般將資料結構分為兩大型別:線性結構和非線性結構。
- 線性結構:有且只有一個根結點;每個結點最多有一個前件,最多隻有一個後件。
- 非線性結構: 如果一個數據結構不是線性結構,稱之為非線性結構。
本文涉及一下內容:
- 四種線性結構的儲存結構:順序表、連結串列、索引、雜湊
- 兩種常見的線性邏輯結構:佇列、棧
- 非線性邏輯結構:迴圈佇列、雙向佇列、雙向迴圈佇列、樹、圖
儲存結構
順序表
順序表是線性表的順序儲存結構,指的是用一組地址連續的儲存單元依次儲存線性表的資料元素。
順序表具備如下兩個基本特徵:
- 順序表中的所有元素所佔的儲存空間是連續的;
- 順序表中各資料元素在儲存空間中是按邏輯順序依次存放的。
假設順序表的每個元素需佔用 個儲存單元,並以所佔的第一個單元的儲存地址作為資料元素的儲存位置。則順序表中第 個數據元素的儲存位置 和第 個數據元素的儲存位置 之間滿足下列關係為:
其中,是順序表的第一個資料元素 的儲存位置,通常稱做順序表的起始位置或基地址。順序儲存結構也稱隨機存取結構。
順序表常見操作(括號中為演算法平均時間複雜度,沒有寫明的具體複雜度依賴不同演算法和運算規則):
插入()、刪除()、查詢、排序、分解、合併、複製()、逆轉()
連結串列
連結串列指線性表的鏈式儲存結構。一組任意的儲存單元儲存線性表的資料元素,因此,為了表示每個資料元素 與其直接後繼資料元素 之間的邏輯關係,對資料元素 來說,除了儲存其本身的資訊(資料域)之外,還需儲存一個變數指示其直接後繼的資訊(指標域)。這兩部分資訊組成資料元素 的儲存映象,稱為結點。 個結點鏈結成一個連結串列。該連結串列就是傳統的單向連結串列。
有時,我們在單鏈表的第一個結點之前附設一個結點,稱之為頭結點,它指向表中第一個結點。頭結點的資料域可 以不儲存任何資訊,也可儲存如線性表的長度等類的附加資訊,頭結點的指標域儲存指向第一個結點的指標。在單鏈表中,取得第 I 個數據元素必須從頭指標出發尋找,因此,連結串列是非隨機存取的儲存結構。
以上提到的連結串列指標域只包括一個指標,指向下一個資料的地址,如果我們將連結串列最後一個結點指標域的指標指向連結串列的頭結點地址,就構成了一個環狀的儲存結構,我們稱作迴圈連結串列。
當然我們可以給每個結點的指標域再新增一個指標,使其指向前一個數據結點的地址,這樣就構成了雙向連結串列,而將頭結點的前一個結點指向尾結點,同時將尾結點的下一個結點指向頭結點就構成了雙向迴圈連結串列。
如果連結串列的尾結點的指標域指向了該連結串列之前的任意一個結點,我們稱該連結串列為有環連結串列。環形連結串列就是其中一個特例
順序表常見操作(括號中為演算法平均時間複雜度,沒有寫明的具體複雜度依賴不同演算法和運算規則):
插入()、刪除()、查詢、排序、分解、合併、複製()、逆轉()
索引
索引儲存除建立儲存結點資訊外,還建立附加的索引表來標識結點的地址。索引表由若干索引項組成。
對於索引的理解最好的例子就是《新華字典》,它建立的2套索引表(拼音、部首)。字典的正文就是從“啊”到“做”的每個字的解釋,有上千頁,就是是資料。而前面的拼音/部首就是索引表,索引表告訴你某個讀音/部首在第幾頁,這就好比是指向資料地址的指標。而索引表可以有一級的也可以是多級的,比如字典中的部首索引就是兩級的。
索引儲存結構是用結點的索引號來確定結點儲存地址,其優點是檢索速度快,缺點是增加了附加的索引表,會佔用較多的儲存空間。
雜湊
雜湊儲存,又稱雜湊(hash)儲存,是一種力圖將資料元素的儲存位置(預留連續儲存區域)與關鍵碼之間建立確定對應關係的查詢技術。雜湊法儲存的基本思想是由結點的關鍵碼值決定結點的儲存地址。雜湊技術除了可以用於儲存外,還可以用於查詢。
雜湊以資料中每個元素的關鍵字 為自變數,通過雜湊函式 計算出函式值,以該函式值作為一塊連續儲存空間的的單元地址,將該元素儲存到函式值對應的單元中。由於該函式值唯一,所以查詢時間複雜度為
線性邏輯結構
線性表
線性表滿足以下特徵:
- 有且只有一個根結點 ,它無前件;
- 有且只有一個終端結點 ,它無後件;
- 除根結點與終端結點外,其他所有結點有且只有一個前件,也有且只有一個後件。線性表中結點的個數 稱 為線性表的長度。當 時稱為空表。
棧
棧實際上也是一個線性表,只不過是一種特殊的線性表。棧是隻能在表的一端進行插入和刪除運算的線性表,通常稱插入、刪除這一端為棧頂(TOP),另一端為棧底(BOTTOM)。當表中沒有元素時稱為棧空。 棧頂元素總是後被插入(入棧)的元素,從而也是最先被移除(出棧)的元素;棧底元素總是最先被插入的元素,從而也是最後才能被移除的元素。所以棧是個 後進先出(LIFO) 的資料結構
棧的基本運算有三種:入棧、出棧與讀棧頂,時間複雜度都是
佇列
佇列是隻允許在一端刪除,在另一端插入的順序表,允許刪除的一端叫做隊頭,用對頭指標 指向對頭元素的下一個元素,允許插入的一端叫做隊尾,用隊尾指標 指向佇列中的隊尾元素,因此,從排頭指標 指向的下一個位置直到隊尾指標 指向的位置之間所有的元素均為佇列中的元素。
佇列的修改是 先進先出(FIFO) 。往隊尾插入一個元素稱為入隊運算。從對頭刪除一個元素稱為退隊運算。
佇列主要有兩種基本運算:入隊運算和退隊運算,複雜度都是
迴圈佇列
在實際應用中,佇列的順序儲存結構一般採用迴圈佇列的形式。所謂迴圈佇列,就是將佇列儲存空間的最後一個 位置繞到第一個位置,形成邏輯上的環狀空間。在實際使用迴圈佇列時,為了能區分隊滿還是佇列空,通常需要增加一個標誌 。
迴圈佇列主要有兩種基本運算:入隊運算和退隊運算,複雜度都是
- 入隊運算
指在迴圈佇列的隊尾加入一個新元素,首先