數據結構與算法之線性表

前言

上一篇《數據結構和算法之時間複雜度和空間複雜度》中介紹了時間複雜度的概念和常見的時間複雜度,並分別舉例子進行了一一說明。這一篇主要介紹線性表。html

線性表屬於數據結構中邏輯結構中的線性結構。回憶一下,數據結構分爲物理結構和邏輯結構,邏輯結構分爲線性結構、幾何結構、樹形結構和圖形結構四大結構。其中,線性表就屬於線性結構。剩餘的三大邏輯結構從此會一一介紹。算法

線性表

基本概念

線性表(List):由零個或多個數據元素組成的有限序列。windows

注意:數組

1.線性表是一個序列。數據結構

2.0個元素構成的線性表是空表。數據結構和算法

3.線性表中的第一個元素無前驅,最後一個元素無後繼,其餘元素有且只有一個前驅和後繼。工具

4.線性表是有長度的,其長度就是元素個數,且線性表的元素個數是有限的,也就是說,線性表的長度是有限的。post

若是用數學語言來進行定義,可以下:

若將線性表記爲(a1,…,ai-1,ai,ai+1,…an),則表中ai-1領先於ai,ai領先於ai+1,稱ai-1是ai的直接前驅元素,ai+1是ai的直接後繼元素。優化

線性表基本操做

InitList(*L): 初始化操做,創建一個空的線性表L。 url

ListEmpty(L): 判斷線性表是否爲空表,若線性表爲空,返回true,不然返回false。

ClearList(*L): 將線性表清空。 GetElem(L,i,*e): 將線性表L中的第i個位置元素值返回給e。

LocateElem(L,e): 在線性表L中查找與給定值e相等的元素,若是查找成功,返回該元素在表中序號表示成功;不然,返回0表示失敗。

ListInsert(*L,i,e): 在線性表L中第i個位置插入新元素e。

ListDelete(*L,i,*e): 刪除線性表L中第i個位置元素,並用e返回其值。

ListLength(L): 返回線性表L的元素個數。

 

對於不一樣的應用,線性表的基本操做是不一樣的,上述操做是最基本的。

對於實際問題中涉及的關於線性表的更復雜操做,徹底能夠用這些基本操做的組合來實現。

兩種不一樣的線性表

咱們知道,數據結構分爲邏輯結構和物理結構,邏輯結構分爲集合結構、線性結構、樹形結構和圖形結構四大類。物理結構分爲順序存儲結構和鏈式存儲結構。我在以前寫的《數據結構和算法》中已經介紹過。

線性表是線性結構的一種,那麼線性表固然也有物理結構,也就是說,線性表有兩種,分別是順序結構的線性表(叫作順序表)和鏈式結構的線性表(叫作鏈表)。

1.順序存儲結構的線性表

順序表是指順序存儲結構的線性表,指的是用一段地址連續的存儲單元依次存儲線性表的數據元素。

順序表表如今物理內存中,也就是物理上的存儲方式,事實上就是在內存中找個初始地址,而後經過佔位的形式,把必定的內存空間給佔了,而後把相同數據類型的數據元素依次放在這塊空地中。注意,這塊物理內存的地址空間是連續的。

舉 個例子,好比C語言中的基本變量的存儲就是連續的存儲在內存中的,好比聲明一個整數i,在64位系統中整數i在內存中佔8字節,那麼系統就會在內存中爲這 個整型變量分配一個長度爲8個字節的連續的地址空間,而後把這個i的二進制形式從高地址向低地址存儲,長度不足時候,最高位用0補齊。

順序表的結構體定義

#define MAXSIZE 20   // 順序表的最大存儲容量 typedef int ElemType; // 順序表存儲的數據類型  typedef struct { ElemType data[MAXSIZE]; // 用數組表示順序表 int length; // 線性表當前長度 } SqList;

 

經過上面用結構體定義順序表,咱們能夠看出順序表的封裝須要三個屬性:

1.存儲空間的起始位置。 數組data的存儲位置就是線性表存儲空間的存儲位置
2.線性表的最大存儲容量。數組長度MAXSIZE
3.線性表的當前長度。length
注意:數組的長度與線性表的當前長度是不同的。數組的長度是存放線性表的存儲空間的總長度,通常初始化後不變。而線性表的當前長度是線性表中元素的個數,是會改變的。

順序表查找元素操做

代碼實現:

順序表插入元素操做

思路以下:

 

1.若是插入位置不合理,拋出異常;

 

2.若是線性表長度大於等於數組長度,則拋出異常或動態增長數組容量;

 

3.從最後一個元素開始向前遍歷到第i個位置,分別將它們都向後移動一個位置;

 

4.將要插入元素填入位置i處;

5.線性表長+1。

代碼實現:

 

順序表刪除元素操做

 思路以下:

1.若是刪除元素的位置不合理,拋出異常。好比用戶刪除第0個位置的元素(線性表是從1開始的)、刪除元素的位置大於線性表的長度也要拋出異常。
2.刪除第i個位置的元素。
3.把第i個位置的元素後面的全部的元素的位置加一。
4.線性表長度減一。
代碼實現:

順序表優缺點

由以上代碼能夠看出:

線性表的順序存儲結構,在存、讀取數據時,不論是在哪一個位置,時間複雜度都是O(1)。而在插入或者刪除時,時間複雜度都是O(n)。
這也就是線性表的順序存儲結構比較適合存取數據,不適合常常插入和刪除數據的應用。
優勢:
1.無需爲了表示表中元素之間的邏輯關係而增長額外的存儲空間(相對於鏈式存儲而言)。
2.能夠快速的存取表中任意位置的元素。
缺點:
1.插入和刪除操做須要移動大量的元素。
2.當線性表長度變化較大時,難以肯定存儲空間的容量。
3.容易形成存儲空間的「碎片」(由於線性表的順序存儲結構申請的內存空間都以連續的,若是由於某些操做(好比刪除操做)致使某個部分出現了一小塊的不連續內存空間,由於這一小塊內存空間過小不可以再次被利用/分配,那麼就形成了內存浪費,也就是「碎片」)
PS:windows系統有磁盤碎片整理工具,而Linux系統沒有,由於Linux系統內核優化的很好,幾乎是沒有磁盤碎片的。
 

2.鏈式存儲結構的線性表

前面咱們講的線性表的順序存儲結構,它最大的缺點就是插入和刪除時須要移動大量元素,這顯然就須要耗費時間。

那咱們能不能針對這個缺陷或者說遺憾提出解決的方法呢?要解決這個問題,咱們就得考慮一下致使這個問題的緣由!

爲何當插入和刪除時,就要移動大量的元素?

緣由就在於相鄰兩元素的存儲位置也具備鄰居關係,它們在內存中的位置是緊挨着的,中間沒有間隙,固然就沒法快速插入和刪除。

線性表的鏈式存儲結構的特色是用一組任意的存儲單元存儲線性表的數據元素,這組存儲單元能夠存在內存中未被佔用的任意位置。

也就是說,鏈式存儲結構的線性表由一個(可使零)或者多個結點(Node)組成。每一個節點內部又分爲數據域和指針域(鏈)。數據域存儲了數據元素的信息。指針域存儲了當前結點指向的直接後繼的指針地址。
由於每一個結點只包含一個指針域,因此叫作單鏈表。顧名思義,固然還有雙鏈表。

單鏈表

鏈式存儲結構中,除了要存儲數據元素信息外,還要存儲它的後繼元素的存儲地址(指針)。

也就是說除了存儲其自己的信息外,還需存儲一個指示其直接後繼的存儲位置的信息。

咱們把存儲數據元素信息的域稱爲數據域,把存儲直接後繼位置的域稱爲指針域。

 

指針域中存儲的信息稱爲指針或鏈。

這兩部分信息組成數據元素稱爲存儲映像,或稱爲結點(Node)。

n個結點連接成一個鏈表,即爲線性表(a1, a2, a3, …, an)的鏈式存儲結構。

 

由於此鏈表的每一個結點中只包含一個指針域,因此叫作單鏈表。

 

對於線性表來講,總得有個頭有個尾,鏈表也不例外。咱們把鏈表中的第一個結點的存儲位置叫作頭指針,最後一個結點指針爲空(NULL)。

單鏈表是線性表中最具表明性的一種,下一篇文章中,本人將會拿出一章來介紹單鏈表,敬請期待!

圖片來源參考自:魚C工做室。感謝魚C工做室貢獻出了這麼好的圖片。
如非特別說明,筆者全部文章都是原創文章。若是您喜歡這篇文章,轉載請註明出處。若是您對數據結構感興趣,請關注我,後續會更新大量精品文章供你們參考!

PS:本篇文章在簡書也有同步更新,你們也能夠移步簡書關注本人,後續會更新更多精品文章!

簡書地址:http://www.jianshu.com/users/93131dfba96a/latest_articles

相關文章
相關標籤/搜索