有序插入時,數組與鏈表效率比較

絕對不是。這確實讓人很不理解,畢竟爲了將某元素插入到數組合適的地方,需要將此地方及以後的元素都要向後平移,而對鏈表來說,簡單地新申請一個節點和改變兩個指針變量的值即可,甚至,我們還可以預先一次性申請一堆節點。但是Programming Pearls(英文版第2版)第137頁列出一張表,證實情況不那麼簡單

表列出數據表明了向相應數據結構中插入m個0~n(n = 1,000,000)之間的隨機數的耗時情況。表中的簡單鏈表指插入元素時採用遞歸,並且每次只申請一個節點空間;無遞歸鏈表去掉遞歸,採用循環;組空間申請指一次性申請m個節點空間

 

數組結構

問題規模(m)

10,000

20,000

40,000

數組

0.6

2.6

11.1

簡單鏈表

5.7

31.2

170.0

無遞歸鏈表

1.8

12.6

73.8

組空間申請鏈表

1.2

5.7

25.4

 

    由圖可以看出,即使是鏈表採用了組空間申請這樣精巧的技術,速度仍然比數組慢一倍!這與我們“當有頻繁的插入操作時最好採用鏈表結構”的常識完全相反。用John Bentley的話說,“something was wrong”。下面是他的分析。

 

    “我首先認爲(鏈表比數組慢)是因爲遞歸太耗時,...,改爲循環之後時間下降了將近三倍。然後我的反應是將內存申請策略改爲一次申請m個節點。這樣有兩個顯著的改進:a)內存申請操作耗時比最簡單內存操作多出大約二個數量級,b)當一次性爲若干節點申請一塊內存時,每個節點只有8字節(4個字節存儲整數,4字節存儲指向下一節點的指針),於是40,000個節點消耗320k內存,這完全可放入二級緩存;而一次申請一塊時每個節點佔用48字節,總共消耗1.9M(比他的二級緩存大)。... 對於數組和鏈表,要插入一個元素,首先要找到該元素應該插入的位置,這必然是一個線性過程;不同的是接下來,數組需要將該位置及以後的元素向後移動,而鏈接不會,那爲什麼鏈表反而更耗時?部分原因是鏈表佔用至少2倍的內存空間:它需要將8字節讀入緩存以獲取4字節的整數。另一個原因是數組的內存是連續的,訪問其元素有很好的可預測性,而鏈表需要滿內存地跳來跳去。”


我覺得,上面的分析任然有很大的侷限性,因爲上面的例子,默認存儲的是一個4byte的整數,但是如果我們將要存儲的數據換成一個結構體的時候,上面的測試數據可能就不存在有效性了。一切取決於實際應用。在選擇數組或鏈表的時候,根據實際情況合理選擇,最好預先做相應的測試,根據實際結果選擇。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章