vector, list, map等容器使用場合是什麼?

如圖,暫且不論map的那個紅黑樹和資料庫索引的B+樹畫法是否正確。

第一個問題,印象中使用map容器的時候數據是直接存在結點data域裡面的,但是資料庫索引樹(按記錄的id建的索引)卻和記錄數據是分離的,這是為什麼?難道上面那個map的示意圖我弄錯了其實它的key和value也是分離的?

第二個問題,vector, list, map的一般使用場景是什麼?我知道它們的區別,但是之前我在實際工作中卻是很隨意使用,我覺得這樣不好。


  1. 順序容器首選 vector,關聯容器首選 unordered_map。
  2. 當這兩個不滿足需求時再考慮別的容器。


瀉藥!

在高速塞車中隨便扯幾句。

第一個問題,資料庫原理我不是很熟悉,但是我隱約感覺,你這個「分離」的理解是不是就理解為內存布局上的不連續?我覺得他們都是通過索引查找數據,這必然是「聯繫」的,沒有什麼分離。map 的節點存的是一個 pair,pair存著key-value。

第二個問題,如果你很清楚他們的區別的話,我覺得不存在什麼隨意使用的情況。map 跟 vector/list 不一樣,他是關聯式容器,而且會根據key排序,所以你需要用到 key-value 這種形式,或者他自動排序這種性質,就用 map。當然某些情況你也可以用vector/list強行做,但是不直觀啊。(另外:如果你的編譯器支持C++17,請不要把 operator[] 當做 儲存/訪問 的方式,用 try_emplace / insert_or_assign / find 這類代替,原因我不講)vector 跟 list,實際應用場合我想不到,從語義上來說,如果你要求迭代器的有效性,就用 list,否則,絕大部分情況,都用 vector 。

頭暈(ノдヽ)


《Effective STL》有一篇明確寫,要用vector,除非你有大量、頻繁、反覆的插入刪除操作,這時候可以用list,然後準備好數據之後,把它轉為vector,用於以後的只讀訪問。

理由是cache missing, page interrupt


第一問題,由於目前我沒讀過任何一個編譯器關於map這裡源碼,暫時不發表意見。。

第二個問題。。個人感覺比較奇怪,vector和list尚且還有可比性,但是他倆和map有啥可比性呢。。map的元素是二元的。。你要存儲大量二元數據(kv)的時候,肯定用不到vector 或 list,而是map(又或multi或unordered)。私以為拿set放到這裡比較更為合適。

map與unordered_map具體如何選擇容器,關鍵看你的使用場景。當你需要按key排序取用值的時候,這個場景比較常見很多網路服務提供的算簽名方式的第一個步驟(第二步拼key,第三步hash)。。這時候就用key唄 。即使碰到了變態,需要按value排序,你也可以自定義比較器不是?

unordered_map無需多言了(名字實在太長,太奇怪,直接叫dict多好),快速取用的散列容器。它的場景比普通map要多。

vector, list,set。。也不多說了,我就不冒充數據結構老師了。

另外關於容器的選擇,你還需要知道一點是,容器是STL的一部分,請不要孤立地考慮容器選擇,很多時候要結合STL的演算法來一起考慮。因為你數據存起來以後,他可能有多個不同的使用場景,單靠容器自身的成員操作是不夠的,通常要結合演算法。這是就又要考慮演算法和容器的兼容性問題。

不過實際工作中看,,貌似也不需要在選擇容器時如此錙銖必較,做到基本合適就OK了。因為在大型的系統中,通過優化系統架構,調整業務邏輯帶來的性能提升,遠大於你在容器細節的選擇上。。


1. 這是個設計問題,所謂的具體問題具體分析,思考一下如果你有多個key指向同一個value(可能是個很大的對象)或你經需要把樹存到硬碟上時應該如何優化。只是簡單的舉例,我也不是很懂資料庫。

2. 使用什麼數據結構和你的需求有關,主要取決於你對各種數據結構操作的需求以及你的數據量(還有你是否真的需要想這麼多,何必去優化一些根本不會跑幾次而且也慢不到哪裡去的函數呢)

如果你需要快速查詢性能,你的選擇有:

a. vector(key為連續的整數或類似的東西)

b. 有序的vector(key可以比較大小)

c. unordered_map(key可以hash)

d. map(key可以比較大小)

e. 還有很多特定需求下的結構,比如trie tree

那麼如何選擇呢,如果a適用你的需求,一般這往往是最佳選擇。如果你在容器里存的元素不多且move的代價不大,那麼b不錯。否則看向c和d,如果你還需要按大小順序遍歷或者按大小範圍查詢,那麼選d。

但這些也不是絕對的,如果你的表是只讀的,那麼map的樹結構就成為了雞肋,怎麼選擇還是得看你對需求的理解以及benchmark。

至於連續結構,有vector、list、deque(注意cpp里deque的實現是比較特殊的,相當於一個vector和list的混合)

vector一般是最佳選擇,但比如你要搞個臨時的表存一堆指針等以後一起釋放,有時候deque能幫你減少一些內存的拷貝。list這個東西比較雞肋,因為在需要鏈表的場合(很少)一般還是自己手寫維護起來更方便。


1 map存(key value)沒錯的。在資料庫index時,value為指向數據的指針。也就是存的是(key,指針),然後指針指向真實的data,所以給你感覺好像key和data不在一起了。

另外注意不要覺得資料庫index是map,只能說stl中的map和資料庫中的index都是藉助樹實現的。其中一個是紅黑,一個是b或b+(如果是b+,那有的中間node就沒有存指針,具體可以看兩種樹的介紹)用不同的樹實現都是有原因的,是由使用目標決定的。

2 list map vector的選擇屬於基本問題。如果你覺得不知道該選什麼,猜測可能是因為需求比較簡單所以沒有選擇的必要?

建議熟悉每種容器的結構,及基本操作的複雜度。另外還有set unordered_xxx multixxx 幾種queue也是常用的,網上搜會很全面,就不打了。


vector 內存連續,可以理解為 C 的數組,吾輩認為 vector& 就是 char * 最好替代品,後者傾向於C表示,前者是Cpp表示,當然,ObjC 的同類表示是NSData,Java 有 StringBuilder。

list 是標準通用列表,本質是模板做的鏈表。vector適合做buffer,list到處都可以用到。

map是k-v對應的字典存儲,跟前兩者不是一種數據結構,用於散列存儲。map&,你看有兩個type,一般T1為k,T2為v。

一般偽代碼表示為 map[T1] = T2

前面的數據結構list vector都是index索引的。

一般偽代碼表示為 list[0] = value


分不清map和hash_map的使用場合情有可原

但問題中的三個是有很明顯區別的, API介面都不一樣啊


都是啥啊,資料庫那個圖不是B+樹,B+樹內部節點不存儲記錄,只有葉節點存,一般會有兩種,一種是葉節點就是一個塊直接存順序的多個記錄,一般是主索引,另一種是葉節點存儲多個順序的key和指向記錄的文件指針,一般是輔助索引。

正式回答問題:

  1. map里節點key、value放在一起,還是用一個指針存數據根本就不重要,本質就是那樣,通過key排序,然後能找到value就可以了。關於B+樹的問題,上面給你解釋了,要重點理解資料庫索引要以磁碟塊作為單元來做節點。
  2. vector是動態數組,list是鏈表,map是紅黑樹,既然你理解它的區別,那應用場景還什麼好難選擇的?搞不清楚怎麼用,說明你不是真的理解了,如果你時間很寶貴,那就聽聽其他答案,記住就行了,不然就好好思考一下它們的實現,就明白為什麼了。


推薦閱讀:

有没有公开的中国历史人物事件数据库?
oracle和mysql這兩個方向不知道如何選擇去學習?
1月22日晚新浪微博服務各種崩潰,發生了什麼?
数据库这么羸弱会不会被取缔?
怎麼理解「premature optimization is the root of all evil」?

TAG:資料庫 | STL | 數據結構 |