鏈表
鏈表的概念
定義:鏈表是一種物理存儲單元上非連續、非順序的存儲結構,由一系列結點(鏈表中每一個元素稱為結點)組成,結點可以在運行時動態生成。
在鏈表的儲存上,每個結點不僅包含所存的元素信息,還包含元素間的邏輯信息。
鏈表的特性
- 不支持隨機訪問:不能通過知道第一個元素的地址(即儲存空間的首地址)可以輕松訪問儲存的所有數據。
- 節點的儲存空間利用率相對順序表較低:鏈表中的每分一個結點需要划出一部分空間來儲存指向下一個結點位置的指針
- 支持儲存空間的動態分配:鏈表中當前結點的位置是由其前驅結點中的地址信息所指示的。其結點可以散落在內存中的任意位置,且不需要一次性地划分所有結點所需的空間給它。
- 在鏈表中進行插入操作無需移動元素(而順序表需要)
鏈表的形式
單鏈表
在每個結點除了包含的數據域外,還包含一個指針域,用以指向其后繼結點。
- 帶頭結點的單鏈表
帶頭結點的單鏈表中,頭指針head指向頭結點,頭結點的值域不含任何信息,從頭結點的后繼結點開始儲存信息。頭指針head 始終不等於NULL,head->next等於NULL的時候,鏈表為空。
- 不帶頭結點的單鏈表
不帶頭結點的單鏈表中的頭指針head直接指向開始結點,當head等於NULL時,鏈表為空。
雙鏈表
雙鏈表就是在單鏈表結點上增添了一個指針域,指向當前節點的前驅。
相比於單鏈表,雙鏈表能夠從終端結點反向走到開始結點。
循環鏈表
- 循環單鏈表
只需要將單鏈表最后一個指針域(空指針)指向鏈表中的第一個結點即可。(如果循環單鏈表帶頭結點,則指向頭結點;不帶頭結點,則指向開始結點)。
循環單鏈表可以實現從任何一個結點出發,訪問鏈表中任何結點。(注意:此處應該區分與順序表隨機訪問的特點。循環單鏈表指的是從一個結點出發,而不是知道一個結點從而迅速找到任何一個結點,因此循環單鏈表不具有隨機訪問特性。)
帶頭結點的循環單鏈表,當head等於head->next時,鏈表為空;不帶頭結點的循環單鏈表,當head等於NULL時,鏈表為空。
- 循環雙鏈表
雙鏈表終端節點的next指針指向鏈表中第一個結點,將鏈表中的第一個結點的prior指針指向終端結點。
不帶頭結點的循環雙鏈表,head等於NULL,鏈表為空
帶頭結點的循環雙鏈表是沒有空指針的,其為空狀態下,head->next與head->prior必然都等於head,故一下四種語句都可判斷為空
head->next == head;
head->prior == head;
head->next == head && head->prior == head;
head->next == head || head->prior == head;
靜態鏈表
靜態鏈表借助一維數組表示。
靜態鏈表結點空間來自於一個結構體數組(一般鏈表結點空間來自整個內存),數組中每個結點含兩個分量:
- 數據元素分量data
- 指針分量(指示了當前結點直接后繼節點在數組中的位置)
注意:靜態鏈表的指針不是通常所說儲存內存地址的指針型變量,而是儲存數組下標的整型變量,其功能類似於指針,故在此稱為指針
順序表與鏈表區別
基於空間比較
- 儲存的分配方式
順序表儲存空間時一次性分配的,鏈表的是多次分配的
- 存儲密度
(注: 存儲密度 = 結點值域所占存儲量/結點結構所占存儲總量)
順序表存儲密度 = 1
鏈表存儲密度 < 1
基於時間的比較
- 存取方式
順序表可以隨機存取,也可以順序存取
鏈表只能順序存取
- 插入/刪除時移動元素個數
順序表平均需要移動一半元素
鏈表不需要移動元素,僅需修改指針