乙個不得不用deque的情況

2021-09-07 23:19:22 字數 2648 閱讀 7296

過去總以為vector和deque差不多,效率方面deque和vector接近,那乾脆用效率高的vector好了。

但我忽略了另一方,乙個事務存在就有它的理由,今天找到程式裡面隱藏的bug給了我不得不用deque的理由,

deque和vector的結構很類似,但它是多段連續空間,如果vector空間不夠的時候,要重新分配空間,並把所有的資料複製到新的空間中去,

deque不會這麼做,它會去另外開闢一塊連續空間去存放資料,所以儲存效率方面deque高於vector,但deque又不同於鍊錶,它可以說是順序儲存結構和鏈式儲存結構的乙個折中方案把,今天我寫了段**,是這樣的結構

vectorarchiveentities; //也許你要問問什麼不用vector,我這裡比較特別,因為要讀寫磁碟的資料,序列化儲存 //迴避了指標的資料讀寫方式,所以用的vector

那麼:entity * ent = &archive[0]; //看似沒問題,其實裡面暗藏殺機

這個archiveentities 如果不改變是沒有問題,但如果序列集又動態新增了資料,恰好沒有預留空間,那麼將導致整個集合重新分配連續空間了,所以那個引用也將「失效了」,這讓我很頭疼,這個時候讓我想起了deque,它真的很棒,不會去重整空間,需要的時候再開闢其他連續的空間,雖然讀的效率降低了,但

這點損失對於我的程式基本可以忽略不計的,io資料本身就很少去遍歷訪問,卻能給程式很好的去「引用」,不用擔心引用失效的情況,這方面deque確實是個很好的選擇

operator 是指通過下標取資料。顯然 list 的複雜度為o(n),非常慢。而 vector、deque 均為 o(1)。讓我們想象下 deque::operator 的實現:

_e deque::operator(int i)

可以看出,deque 只比 vector 多了一次記憶體訪問。

空間效能分析

push_back

vector

很不幸,如果 vector 採用 n*2 的記憶體增長模型(通常如此),那麼在最差的情況下,空間複雜度就是 2*n ,最好的情況下為 n(所有的記憶體都用上了)。平均來講,空間複雜度為 1.5*n .也就是說,通常差不多有一半的記憶體是被浪費的。

list

list 的空間浪費與 vector 相比不遑多讓。它的空間複雜度為 (1 + sizeof(pointer)*2/sizeof(_e))*n.如果我們讓 list 儲存的元素為 pointer(即 _e = pointer),那麼空間複雜度為 3*n,比 vector 還浪費。

deque

deque 的最差情況下的空間複雜度為 n + sizeof(pointer)*2*n/(blocksize*sizeof(_e))(這裡假設vector也採用 2*n 增長模型,平均複雜度則將式中2改為1.5即可)。如果我們儲存的元素為 pointer(即 _e = pointer),並且blocksize取512,那麼空間複雜度為 n + n/256.也就是說最差情況下只浪費了 n/256 的記憶體。

deque的其他特性

元素位址不變

由於 deque 並不進行資料搬移,帶來乙個有意思的特性,就是 deque 的元素位址在只有 push_back/push_front,沒有 insert/erase 時,可保持元素位址不變。

需要注意的是,vector 並不具備這樣的特性。如下的**是不合法的:

std::vectorvec;

...int& elem = vec[i];

vec.push_back(100);

elem = 99; // error: can't access elem since vec was changed! 

std::dequedq;

...int& elem = dq[i];

dq.push_back(100);

elem = 99; // ok! 

std::dequedq;

...std::deque::iterator it = dq.begin() + i;

dq.push_back(100);

*it = 99; // error: can't access iterator since deque was changed!

結論通過 vector, list, deque 的時間、空間效能對比,我們可以看出,應該提倡盡可能使用 deque 這個容器。特別是,如果要承受海量資料,deque 是最合適的人選了。

依賴於乙個容器是否分配記憶體本身就是你的問題,不是該不該vector還是queue的問題。如果想避免分配記憶體帶來的問題,請用vector>。

deque 不能 memcpy

stl只是乙份標準還不是實現,作為vector來講,它設計目標應該是作為乙個大小伸縮的陣列,比如&v[0]可以當作乙個陣列的指標(如果!v.empty()的話),而deque則不行;deque為了能夠以常數時間在順序容器的頭部及尾部進行push操作而設計的,但這個設計的代價通常很大,應該並不是你所想像的二維陣列的形式,比如sgi的deque設計就採用了一種類似於檔案系統中二級表的方式,其直接結果就是迭代器操作的代價很高。現實程式中你會發現很少有人會用deque,這固然有書中介紹比較少的原因,但也與其操作代價較高是分不開的。

我的意見是,除非不得以,否則使用vector而不要用deque;

你的這種情況,我建議你可以自己寫乙個容器,那怕是用memove,通常也會比std::vector快很多的

deque用的不當,會造成記憶體急劇消耗!

那些你不得不用的好外掛程式!

本期我們就功能開發再給大家推薦幾個非常省心的工具,侑虎君親測有效!效能非常高效。如下圖,在紅公尺2只要1.16ms即可完成整個函式的呼叫,非常快速。雖然該外掛程式目前僅支援ogg和o 格式,但是我們可以通過工具把其他格式轉換成o 格式匯入unity使用。為了增加角色運動的真實代入感,我們常常需要某些...

Sublime Text3,你不得不用的編輯器

從選單 view show console 或者 ctrl 快捷鍵,調出 console。將以下 python 貼上進去並 enter 執行,不出意外即完成安裝。以下提供 st3 和 st2 的安裝 sublime text 3 import urllib.request,os pf package...

Unity 那些你不得不用的好外掛程式!

繼上期發分享 好外掛程式讓你事半功倍 資源篇 本期我們就功能開發再給大家推薦幾個非常省心的工具,侑虎君親測有效!效能非常高效。如下圖,在紅公尺2只要1.16ms即可完成整個函式的呼叫,非常快速。雖然該外掛程式目前僅支援ogg和ogv格式,但是我們可以通過工具把其他格式轉換成ogv格式匯入unity使...