順序表與鍊錶是非常基本的資料結構,它們可以被統稱為線性表。
線性表(linear list)是由 n(n≥0)個資料元素(結點)a[0],a[1],a[2]…,a[n-1] 組成的有限序列。順序表和煉表,是線性表的不同儲存結構。它們各自有不同的特點和適用範圍。針對它們各自的缺點,也有很多改進的措施。
順序表一般表現為陣列,使用一組位址連續的儲存單元依次儲存資料元素,如圖 1 所示。它具有如下特點:
圖 1 順序表
順序表最主要的問題就是要求長度是固定的,可以使用倍增-複製的辦法來支援動態擴容,將順序表變成「可變長度」的。
具體做法是初始情況使用乙個初始容量(可以指定)的陣列,當元素個數超過陣列的長度時,就重新申請乙個長度為原先二倍的陣列,並將舊的資料複製過去,這樣就可以有新的空間來存放元素了。這樣,列表看起來就是可變長度的。
乙個簡單的實現如下所示,初始的容量為 4。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include
struct
sqlist
void
doublecapacity()
void
add(
int
value)
items[size++] = value;
}
};
這個辦法不可避免的會浪費一些記憶體,因為陣列的容量總是倍增的。而且每次擴容的時候,都需要將舊的資料全部複製乙份,肯定會影響效率。不過實際上,這樣做還是直接使用鍊錶的效率要高,具體原因會在下一節進行分析。
鍊錶,類似它的名字,表中的每個節點都儲存有指向下乙個節點的指標,所有節點串成一條鏈。根據指標的不同,還有單鏈表、雙鏈表和迴圈鍊錶的區分,如圖 2 所示。
圖 2 鍊錶
單鏈表是只包含指向下乙個節點的指標,只能單向遍歷。
雙鏈錶即包含指向下乙個節點的指標,也包含指向前乙個節點的指標,因此可以雙向遍歷。
迴圈單鏈表則是將尾節點與首節點鏈結起來,形成了乙個環狀結構,在某些情況下會非常有用。
還有迴圈雙鏈表,與迴圈單鏈表類似,這裡就不再贅述。
由於鍊錶是使用指標將節點連起來,因此無需使用連續的空間,它具有以下特點:
在上一節說到,利用倍增-複製的辦法,同樣可以讓順序表長度可變,而且效率比鍊錶還要好,下面就簡單的實現乙個單鏈表來驗證這一點,至於元素插入的順序就不要在意了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include
#include
struct
node ;
struct
llist
};
int
main()
long
end =
clock
();
printf
(
"sequence list: %d\n"
, end - start);
start =
clock
();
for
(
int
i = 0;i < size;i++)
end =
clock
();
printf
(
"linked list: %d\n"
, end - start);
return
0;
}
在我的電腦上,鍊錶的耗時大約是順序表的 4~8 倍。會這樣,是因為陣列只需要很少的幾次大塊記憶體分配,而鍊錶則需要很多次小塊記憶體分配,記憶體分配操作相對是比較慢的,因而大大拖慢了鍊錶的速度。這也是為什麼會出現記憶體池。
因此,鍊錶並不像理論分析的那樣美好,在實際應用中要受很多條件制約,一般情況下還是安心用順序表的好。
鍊錶和順序表的區別
都屬於線性表,都是線性結構 順序表 順序儲存 優點 支援隨機訪問 儲存密度高 缺點 大片連續空間分配不方便,改變容量不方便 鍊錶 鏈式儲存 優點 離散的小空間分配方便,改變容量方便 缺點 不可隨機訪問,儲存密度低 創銷 增刪改 查 順序表 順序儲存 需要預分配大片連續空間。若分配空間過小,則之後不方...
鍊錶和順序表
順序表一般可以分為 1 靜態順序表 使用定長陣列儲存 2 動態順序表 使用動態開闢的數值儲存 順序表的靜態儲存 define n 100 typedef int sldatatype typedef struct seqlist seqlist 順序表的動態儲存 typedef struct seq...
鍊錶和順序表習題(一)
鍊錶順序表 每個元素的訪問 每個節點都需要通過指標找到記憶體然後載入到快取中 記憶體訪問時,不需要多次從記憶體到快取的步驟 頭插,頭刪,中間位置 直接增加或刪除節點 在插入或刪除之前要先對之後的資料進行挪動 尾插,尾刪 需要對空間進行操作 直接對資料進行操作,空間是之前一次性開闢好的 空間操作 每次...