順序表總結

順序表總結

1.線性表

零個或多個元素的有限序列。或者 線性表是由n個元素組成的有限序列。算法

咱們都知道了線性表元素之間是有序的,一一對應的。下面是線性表的兩種實現。數組

1.2.順序表

物理儲存:用一段地址連續的存儲單元依次存儲線性表的數據元素。既然是連續內存,咱們就能夠想到數組。因此咱們能夠用數組來實現順序表。數據結構

重點注意:既然是用數組,咱們都知道數組字定義時,必須聲明數組的大小。因此這裏引出兩個概念。.net

數組長度: 咱們在定義結構體時的數組申明大小指針

順序表長度: 定義變量後,變量存放數據的多少。索引

由此能夠看出,順序表的長度必定小於等於數組長度。內存

線性表元素的序號和存放它的數組下標之間存在對應關係:因爲咱們數數都是從1開始數的,線性表的定義也不能避免,起始也是1,可C語言中的數組倒是從0開始的第一個下標,因而線性表的第i個元素是要存儲在數組下標爲i-1的位置。get

 

既然順序表有長度,是否是須要一個變量來記錄這個長度?it

這樣咱們的順序表的結構也就出來了。ast

struct list

{

int  data[20];  //存放數據

/*--------------------------------------*/

Int len;;      // 記錄順序表的長度

};

這裏要注意的是

/*------------*/前面:是能夠寫多個,任意類型的數據(通常多個數據用結構體來包裹起來,因此通常都是結構體類型)。

/*------------*/後面:的是記錄順序表的長度,也就是存儲元素的個數。

 

1.2.1順序表插入

 

咱們都知道順序表的存儲是用數組實現的。

因此咱們在插入的時候,須要數組元素日後移動。空一個位置來進行插入。

1. 從最後一個位置開始向前遍歷到第i個位置,也就是咱們須要插入的位置。分別將他們向後移動一位。這樣就會空出一個位置來。

2. 咱們在第i個位置來插入這個元素。

3. 不要忘記---->順序表長度加1

 

圖示:

 

圖 5-1  插入示意圖

在圖5-1中,紅色方框表示空出來的位置。咱們須要在4這個位置,插入

注意增長的元素就是咱們要刪除的元素。

代碼實現:

要注意數組下標和實際位置之間的關係。咱們的循環i控制的是數組的下標。

for(i = list.len; i >= x; i--)

{

list.data[i] = list.dat[i-1];

}

List.data[x-1] = ??;//這裏賦值,或者scanf輸入data若是是結構體,就給其成員變量分別來賦值。

List.len++;

 

1.2.2 順序表的刪除

 

在執行刪除操做時,咱們只需將數組從刪除的位置,向前移動就能夠了。

1. 從刪除的位置開始,向後遍歷,直到最後一個元素位置。分別將他們向前移動一個位置。

2. 不要忘記----->順序表長度減1

圖示:

圖 5-2 刪除示意圖

在圖5-2中紅色數字表示要刪除的數字。咱們把位置爲5的元素刪除。

注意刪除元素後,順序表的長度減1

代碼實現:

for(i = x-1; i < list.len; i++)

{

list.data[i] = list.dat[i+1];

}

List.len--;

1.2 單鏈表

物理存儲:鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是經過鏈表中的指針連接次序實現的。

鏈表由一系列結點(鏈表中每個元素稱爲結點)組成,結點能夠在運行時動態生成。每一個結點包括兩個部分:一個是存儲數據元素的數據域,另外一個是存儲下一個結點地址的指針域。

由此咱們能夠總結出來鏈表的結構體這也就是所謂的節點:

struct linklist

{

Int data;

struct linklist *next;

};     

typedef struct linklist * linklist;  // 這裏的linklist通常取名爲咱們實際鏈表的名稱這

在這裏咱們須要特別注意的是頭節點和頭指針之間的區別。固然還有最後一個節點的指針指向NULL。

頭指針:

//TODO

頭結點:

//TODO

1.2.1單鏈表的插入

 

圖 5 - 3 單鏈表的插入

如圖所示:要將S節點插入。此時我要注意的是不能將p 後面的元素丟失

代碼實現:

1.  S -> next = P -> next;  // 注意p後面的元素不能丟失,因此先讓P後的元素掛到s上去。2.  P -> next = s;        // 而後讓P和 s創建關係

1.2.2 單鏈表的刪除

 

圖 5 -4 單鏈表刪除

如圖所示:咱們要刪除的是p後的一個元素。咱們只要把p的next域指向他的下下個元素。

代碼實現:

p->next = p->next->next;

//TODO...

1.3 順序表和單鏈表的比較

1.3.1 順序表特色:

  1. 邏輯上相鄰的數據元素,物理存儲位置也相鄰,而且,順序表的存儲空間須要預先分配
  2. 存儲空間連續,即容許元素的隨機訪問。
  3. 存儲密度大,內存中存儲的所有是數據元素。
  4. 要訪問特定元素,可使用索引訪問,時間複雜度爲 O(1)。
  5. 要想在順序表中插入或刪除一個元素,都涉及到以後全部元素的移動,所以時間複雜度爲 O(n)。

優勢:

ü  存取速度高效,經過下標來直接存儲,隨機訪問的特色。

ü  方法簡單,各類高級語言中都有數組,容易實現。

ü  不用爲表示節點間的邏輯關係而增長額外的存儲開銷。

缺點:

  • 在順序表中作插入、刪除操做時,平均移動表中的一半元素,所以對n較大的順序表效率低。
  • 須要預先分配足夠大的存儲空間,估計過大,可能會致使順序表後部大量閒置;預先分配太小,又會形成溢出。

1.3.2 單鏈表特色

長度不固定,能夠任意增刪。

存儲空間不連續,數據元素之間使用指針相連,每一個數據元素只能訪問周圍的一個元素(根據單鏈表仍是雙鏈表有所不一樣)。

存儲密度小,由於每一個數據元素,都須要額外存儲一個指向下一元素的指針(雙鏈表則須要兩個指針)。

要訪問特定元素,只能從鏈表頭開始,遍歷到該元素,時間複雜度爲 O(n)。

在特定的數據元素以後插入或刪除元素,不涉及到其餘元素的移動,所以時間複雜度爲 O(1)。雙鏈表還容許在特定的數據元素以前插入或刪除元素。

優勢:

ü  插入和刪除速度快,保留原有的物理順序,好比:插入或者刪除一個元素時,只須要改變指針指向便可

缺點:

  • 要佔用額外的存儲空間存儲元素之間的關係,存儲密度下降。存儲密度是指一個節點中數據元素所佔的存儲單元和整個節點所佔的存儲單元之比。
  • 鏈表不是一種隨機存儲結構,不能隨機存取元素。

 

3、順序表與鏈表的優缺點切好相反,那麼在實踐應用中怎樣選取存儲結構呢?一般有如下幾點考慮:

  (1)順序表的存儲空間是靜態分配的,在程序執行以前必須明確規定它的存儲規模,也就是說事先對「MaxSize」要有合適的設定,設定過大會形成存儲空間的浪費,太小形成溢出。所以,當對線性表的長度或存儲規模難以估計時,不宜採用順序表。然而,鏈表的動態分配則能夠克服這個缺點。鏈表不須要預留存儲空間,也不須要知道表長如何變化,只要內存空間尚有空閒,就能夠再程序運行時隨時地動態分配空間,不須要時還能夠動態回收。所以,當線性表的長度變化較大或者難以估計其存儲規模時,宜採用動態鏈表做爲存儲結構。

  但在鏈表中,除數據域外海須要在每一個節點上附加指針。若是節點的數據佔據的空間小,則鏈表的結構性開銷就佔去了整個存儲空間的大部分。當順序表被填滿時,則沒有結構開銷。在這種狀況下,順序表的空間效率更高。因爲設置指針域額外地開銷了必定的存儲空間,從存儲密度的角度來說,鏈表的存儲密度小於1.所以,當線性表的長度變化不大並且事先容易肯定其大小時,爲節省存儲空間,則採用順序表做爲存儲結構比較適宜。

  (2)基於運算的考慮(時間)

  順序存儲是一種隨機存取的結構,而鏈表則是一種順序存取結構,所以它們對各類操做有徹底不一樣的算法和時間複雜度。例如,要查找線性表中的第i個元素,對於順序表能夠直接計算出a(i)的的地址,不用去查找,其時間複雜度爲0(1).而鏈表必須從鏈表頭開始,依次向後查找,平均須要0(n)的時間。因此,若是常常作的運算是按序號訪問數據元素,顯然順表優於鏈表。

  反之,在順序表中作插入,刪除時平均移動表中一半的元素,當數據元素的信息量較大並且表比較長時,這一點是不該忽視的;在鏈表中做插入、刪除,雖然要找插入位置,但操做是比較操做,從這個角度考慮顯而後者優於前者。

  (3)基於環境的考慮(語言)

順序表容易實現,任何高級語言中都有數組類型;鏈表的操做是基於指針的。相對來說前者簡單些,也用戶考慮的一個因素。

結論:

  總之,兩種存儲結構各有長短,選擇哪種由實際問題中的主要因素決定。一般「較穩定」的線性表,即主要操做是查找操做的線性表,適於選擇順序存儲;而頻繁作插入刪除運算的(即動態性比較強)的線性表適宜選擇鏈式存儲。

相關文章
相關標籤/搜索