在c++中,容器被定義為:在資料儲存上,有一種物件型別,它可以持有其他物件或指向其他物件的指標,這種物件型別就叫做容器。簡單理解,即容器就是儲存其他物件的物件。而且,這種「物件」還有處理「其他物件」的方法。
容器是隨著物件導向語言的誕生而提出的,它甚至被認為是早期物件導向語言的基礎。現在幾乎所有物件導向語言中都伴隨著乙個容器,c++中則是標準模版庫(stl)。
stl 對定義的通用容器分三類:順序性容器、關聯式容器和容器介面卡。
順序性容器
是一種各元素之間有順序關係的線性表,是一種線性結構的可序群集。順序性容器中的每個元素均有固定的位置,除非用刪除或插入的操作改變這個位置。這個位置和元素本身無關,而和操作的時間和地點有關,順序性容器不會根據元素的特點排序而是直接儲存了元素操作時的邏輯順序。比如我們一次性對乙個順序性容器追加三個元素,這三個元素在容器中的相對位置和追加時的邏輯次序是一致的。
關聯式容器
和順序性容器不一樣,關聯式容器是非線性的樹結構,更準確的說是二叉樹結構。各元素之間沒有嚴格的物理上的順序關係,也就是說元素在容器中並沒有儲存元素置入容器時的邏輯順序。但是關聯式容器提供了另一種根據元素特點排序的功能,這樣迭代器就能根據元素的特點「順序地」獲取元素。關聯式容器另乙個顯著的特點是它是以鍵值的方式來儲存資料,就是說它能把關鍵字和值關聯起來儲存,而順序性容器只能儲存一種(可以認為它只儲存關鍵字,也可以認為它只儲存值)。
容器介面卡 是乙個比較抽象的概念,c++的解釋是:介面卡是使一事物的行為類似於另一事物的行為的一種機制。容器介面卡是讓一種已存在的容器型別採用另一種不同的抽象型別的工作方式來實現的一種機制。其實僅是發生了介面轉換。那麼你可以把它理解為容器的容器,它實質還是乙個容器,只是他不依賴於具體的標準容器型別,可以理解是容器的模版。或者把它理解為容器的介面,而介面卡具體採用哪種容器型別去實現,在定義介面卡的時候可以由你決定。
1 vector
常用介面:
//初始化
vectorvec; //預設初始化,空
vectorvec2(vec); //使用vec初始化vec2
vectorvec3(3); //初始化3個值為0的元素
vectorvec4(4, 1); //初始化4個值為1的元素
vectorvec5(5, "null"); //初始化5個值為null的元素
//常用的操作方法
vec.push_back(3); //向末尾新增元素3
vec.begin();//返回指向初始位置的迭代器
vec.end(); //返回指向末尾下一位置的迭代器
vec.size(); //當前vector容器真實占用的大小
vec.capacity();//capacity是指能允許的最大元素數,即預分配的記憶體空間。
vec.empty(); //判斷是否為空
cout << vec[0] << endl; //取得第乙個元素 支援
vec.insert(vec.end(), 5, 3); //從末尾下一位置插入5個值為3的元素
vec.pop_back(); //刪除末尾元素
vec.erase(vec.begin(), vec.end());//刪除之間的元素,其他元素前移
cout << (vec == vec2) ? true : false; //判斷是否相等==、!=、>=、<=...
vec.clear(); //清空元素
vectorvs1(3);
vectorvs2(5);
vs1.swap(vs2); //執行後,vs1中5個元素,而vs2則存3個元素
要點
可以直接訪問任何元素。
線性順序結構。可以指定一塊連續的空間,也可以不預先指定大小,空間可自動擴充套件,也可以像陣列一樣被操作,即支援操作符和vector.at(),因此可看做動態陣列,通常體現在追加資料push_back()和刪除末尾資料pop_back()。
當分配空間不夠時,vector會申請一塊更大的記憶體塊(以2的倍數增長,vs是這樣),然後將原來的資料拷貝到新記憶體塊中並將原記憶體塊中的物件銷毀,最後釋放原來的記憶體空間。因此如果vector儲存的資料量很大時會很消耗效能,因此在預先知道它大小時效能最優。
節省空間。因為它是連續儲存,在儲存資料的區域是沒有浪費的,但實際上大多數時候是存不滿的,因此實際上未儲存的區域是浪費的。
在內部進行插入和刪除的操作效率低。由於vector內部按順序表結構設計,因此這樣的操作基本上是被禁止的,它被設計成只能在後端進行追加和刪除操作。
2 list
常用介面:
//初始化
listlst1; //建立空list
listlst2(3); //建立含有三個元素的list
listlst3(3, 2); //建立含有三個元素的值為2的list
listlst4(lst2); //使用lst2初始化lst4
//常用的操作方法
lst1.assign(lst2.begin(), lst2.end()); //分配值
lst1.push_back(10); //新增值
lst1.pop_back(); //刪除末尾值
lst1.begin(); //返回首值的迭代器
lst1.end(); //返回末尾位置下一位的迭代器
lst1.clear();//清空值
bool isempty1 = lst1.empty(); //判斷為空
lst1.erase(lst1.begin(), lst1.end()); //刪除元素
lst1.front(); //返回第乙個元素的引用
lst1.back(); //返回最後乙個元素的引用
lst1.insert(lst1.begin(), 3, 2); //從指定位置插入3個值為2的元素
lst1.remove(2); //相同的元素全部刪除
lst1.reverse(); //反轉
lst1.size(); //含有元素個數
lst1.sort(); //排序,需要自己寫過載操作符<
lst1.unique(); //刪除相鄰重複元素
要點
線性鍊錶結構。
其資料由若干個節點構成,每個節點包括乙個資訊塊(即實際儲存的資料)、乙個前驅指標和乙個後驅指標。無需分配指定的記憶體大小且可任意伸縮,因此它儲存在非連續的記憶體空間中,並且由指標將有序的元素鏈結起來。因而相比vector它也佔更多的記憶體。
根據其結構可知隨機檢索的效能很差,vector是直接找到元素的位址,而它需要從頭開始按順序依次查詢,因此檢索靠後的元素時非常耗時。即不支援操作符和.at()。
由於list每個節點儲存著它在鍊錶中的位置,插入或刪除乙個元素僅對最多三個元素有所影響,因此它可以迅速在任何節點進行插入和刪除操作。
3 deque
是一種優化了的、對序列兩端元素進行新增和刪除操作的基本序列容器。它允許較為快速地隨機訪問,但它不像vector 把所有的物件儲存在一塊連續的記憶體塊,而是採用多個連續的儲存塊,並且在乙個對映結構中儲存對這些塊及其順序的跟蹤。向deque 兩端新增或刪除元素的開銷很小。它不需要重新分配空間,所以向末端增加元素比vector 更有效。
實際上,deque 是對vector 和list 優缺點的結合,它是處於兩者之間的一種容器。
常用介面與vector和list相似
要點:
(1) 隨機訪問方便,即支援[ ] 操作符和vector.at() ,但效能沒有vector 好;
(2) 可以在內部進行插入和刪除操作,但效能不及list ;
(3) 可以在兩端進行push 、pop ;
vector 是一段連續的記憶體塊,而deque 是多個連續的記憶體塊, list 是所有資料元素分開儲存,可以是任何兩個元素沒有連續。
vector 的查詢效能最好,並且在末端增加資料也很好,除非它重新申請記憶體段;適合高效地隨機儲存。若已經知道需要儲存元素的數目, 則選擇vector。
list 是乙個鍊錶,任何乙個元素都可以是不連續的,但它都有兩個指向上一元素和下一元素的指標。所以它對插入、刪除元素效能是最好的,而查詢效能非常差;適合 大量地插入和刪除操作而不關心隨機訪問的需求。若需要隨機插入/刪除(不僅僅在兩端),則選擇list
deque 是介於兩者之間,它兼顧了陣列和鍊錶的優點,它是分塊的鍊錶和多個陣列的聯合。 如果你需要隨機訪問又關心兩端資料的插入和刪除,那麼deque 是最佳之選。
C 順序容器
一 順序容器型別 順序容器 vector list deque 介面卡 stack queue priority queue 使用這些容器都必須使用相應的標頭檔案 二 容器元素初始化 cc 建立乙個名為c的空容器 cc c2 建立容器c2的副本 cc b,e 建立c,其元素是迭代器b和e的範圍內的副...
C 順序容器
1 概述 乙個容器就是一些特定型別物件的集合。順序容器型別 描述vector 可變大小陣列,支援快速訪問,在尾部之外的地方插入或刪除時可能很慢 deque 雙端佇列。支援快速訪問,在頭尾插入刪除會很快。list 雙向列表。只支援雙向順序訪問。插入刪除很快 forward list 單向列表。只支援單...
C 順序容器
一 各個順序容器效能差異主要體現在一下兩個方面 1.在容器中任意位置新增和刪除元素的代價 2.隨機訪問容器中元素的代價 vector list deque forward list array string vector是可變大小陣列,支援快速隨機訪問,在尾部插入和刪除元素較為方便 list是雙向鍊...