C 知識總結 P03 容器

2022-09-13 01:12:11 字數 4258 閱讀 7334

容器可以分為三類:序列式容器、關聯容器、無序容器,此外還有一些容器介面卡。

arrayvectorarray與c中的陣列類似,是一種大小固定的儲存連續的容器;vector也是儲存連續的,但它的長度可以動態調整。相對於陣列型別,這兩種容器更為安全。由於arrayvector都是連續儲存的容器,能夠高效地利用索引訪問元素,但在中間部分插入/刪除元素比較低效。

deque:一種雙端佇列,也是一種連續儲存的容器,能夠高效地在首尾部新增/刪除元素,但在中間部分插入/刪除元素比較低效。

listforward_listlist是由雙向鍊錶實現的,forward_list是由單向鍊錶實現的,因此這兩種容器能夠高效地插入/刪除元素,但很難進行隨機訪問。

mapmap型別儲存鍵值對,通常是以二叉樹實現的,預設以 key 作為比較的依據。map中的 key 不允許重複,而multimapmap的唯一的區別是元素可以重複。

setset型別只儲存鍵值,其它特性與map相同,multisetset的唯一區別是元素可以重複。

由於關聯容器的底層實現是二叉樹(紅黑樹),因此預設情況下關聯容器中的 keys 是有序的。如果使用關聯容器時對排序沒有需求,可以選擇下面的無序容器。

關聯容器中的四種型別都有對應的無序版本:unordered_map,unordered_multimap,unordered_set,unordered_multiset;無序容器通常是以雜湊表實現的。

stack預設的容器是dequequeue預設的容器是dequepriority_queuequeue功能類似,但是會按照壓入元素的值排序,彈出值最大的元素。預設使用的容器是vector

根據《c++標準庫》中的描述,預設情況下應該選擇vector,如果需要經常在首尾部插入或移除元素,應該選擇deque,如果需要經常在中間部分插入或移除元素,應該選擇list

如果需要經常查詢元素,應該選擇unordered_set,如果需要使用鍵值對,應該選擇unordered_map,如果在上述兩種場景下,需要滿足有序,應該選擇set/map

容器實現了大量的功能,以成員函式的形式提供這些功能,這裡不在贅述,可以檢視 c++ reference / container。但是僅僅閱讀文件可能無法弄清楚這些成員函式的具體表現,需要在實踐中多累積經驗。

下面是一些我認為靈活使用的方法。

pair 與 tuple

儘管pair提供了first,second來訪問元素,但是還可以使用get()函式來訪問pair,tuple, 甚至array的值,並且該函式還可以作為左值使用get<1>(p) = 10

pair,tuple都提供來比較的能力,按照先比較第乙個元素,相等時再比較第二個元素,……,以這樣的順序進行比較。

array

array.data()會返回指向首元素的指標,這樣就可以像使用陣列一樣處理 array 的資料。如:

arraya ;

int* p = a.data();

for (int i = 0; i < 10; ++i)

vector也提供了這個功能。

vector 與 deque

vectordeque非常相似,只有在雙端插入移除元素的需求時才會使用deque。儘管vector也提供來訪問首個元素的成員函式front,但是沒有像deque一樣提供插入移除首個元素的成員函式。

借助 initlist 來實現初始化乙個值的容器。

// 如果想初始化乙個 大小為 n 的 vector / deque

vectorvec(n);

// 如果想初始化乙個 第乙個元素為 n 的 vector / deque

vectorvec();

list 與 forward_list

相比與前面的vectordequelistforward_list增加來很多不同的能力:排序 sort,逆序 reverse,去重 unique,合併 merge,移動元素 splice,去除元素 remove 等。

forward_list沒有實現size(),原因可能是由於這種容器的設計目的是快速的插入,每次插入操作都去維護乙個儲存 size 的變數顯然會降低效率;而每次獲得 size 都遍歷一遍鍊錶的實現也是低效的,因為人們容易濫用size()成員函式。索性就沒有實現,而且對於使用者而言也不難自己實現。

map 與 multimap

map中的元素是有序的,在map模板中,除前兩個引數用來指定 key 與 value 的型別外,還可以提供第三個引數,用於指定排序時使用的比較方法。因此可以有兩種方式來改變預設的排序規則:1) 指定map模板中的排序引數;2) 修改所使用型別的比較函式。

預設的排序準則是std::less<>,如果像降序排列,可以使用std::greater<>,尖括號內為 key 的型別。或者想使用自定義的排序準則,可以自定義乙個比較的函式:

struct strlencmp 

};mapm;

儘管使用這樣自定義的函式甚至可以實現以 value 值進行排序,但是map中只能保證 key 值唯一,不能保證 value 值唯一,因此使用 value 作為排序依據得到的排序結果無法保證。如果真的需要使用 value 排序,可以將 pair 放入乙個 vector 中進行排序。

set 與 multiset

setmap同理,也可以設定排序準則。

unordered 容器

unordered 容器可以在模板引數中指定乙個 hash 函式,也可以在模板引數中指定乙個用於比較相等的函式,對於小型程式用的的概率不是很大,使用預設的引數就好。

補充:bitset

bitset用來儲存一串布林值,使用vector也可以。具體的用法:

bitset<4> flag("1100");

bitset<16> flags(0xffff);

這種工具提供了下標訪問,翻轉 flip,以及用於檢查全部位的 any all。

列表初始化為 c++ 提供來統一的初始化方式。不管是基本型別,還是容器,以及自定義的型別,都可以使用列表初始化。在自定義型別中的建構函式中使用初始化列表,那麼就可以使用列表初始化來進行,這兩個是對應的。

P03 多重揹包問題

有n種物品和乙個容量為v的揹包。第i種物品最多有n i 件可用,每件費用是c i 價值是w i 求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。這題目和完全揹包問題很類似。基本的方程只需將完全揹包問題的方程略微一改即可,因為對於第i種物品有n i 1種策略 取0件,取1件...

P03 多重揹包問題

有n種物品和乙個容量為v的揹包。第i種物品最多有n i 件可用,每件費用是c i 價值是w i 求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。這題目和完全揹包問題很類似。基本的方程只需將完全揹包問題的方程略微一改即可,因為對於第i種物品有n i 1種策略 取0件,取1件...

P03 多重揹包問題

有n種物品和乙個容量為v的揹包。第i種物品最多有n i 件可用,每件費用是c i 價值是w i 求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。這題目和完全揹包問題很類似。基本的方程只需將完全揹包問題的方程略微一改即可,因為對於第i種物品有n i 1種策略 取0件,取1件...