map和set都是c++的關聯容器,其底層實現都是紅黑樹(rb-tree)。由於 map 和set所開放的各種操作介面,rb-tree 也都提供了,所以幾乎所有的 map 和set的操作行為,都只是轉調 rb-tree 的操作行為。
map和set區別在於:
(2)set的迭代器是const的,不允許修改元素的值;map允許修改value,但不允許修改key。其原因是因為map和set是根據關鍵字排序來保證其有序性的,如果允許修改key的話,那麼首先需要刪除該鍵,然後調節平衡,再插入修改後的鍵值,調節平衡,如此一來,嚴重破壞了map和set的結構,導致iterator失效,不知道應該指向改變前的位置,還是指向改變後的位置。所以stl中將set的迭代器設定成const,不允許修改迭代器的值;而map的迭代器則不允許修改key值,允許修改value值。
stl的分配器用於封裝stl容器在記憶體管理上的底層細節。在c++中,其記憶體配置和釋放如下:
new運算分兩個階段:(1)呼叫
::operator new
配置記憶體;(2)呼叫物件建構函式構造物件內容
delete運算分兩個階段:(1)呼叫物件希構函式;(2)呼叫
::operator delete
釋放記憶體
為了精密分工,stl allocator將兩個階段操作區分開來:記憶體配置有alloc::allocate()負責,記憶體釋放由alloc::deallocate()負責;物件構造由::construct()負責,物件析構由::destroy()負責。
同時為了提公升記憶體管理的效率,減少申請小記憶體造成的記憶體碎片問題,sgi stl採用了兩級配置器,當分配的空間大小超過128b時,會使用第一級空間配置器;當分配的空間大小小於128b時,將使用第二級空間配置器。第一級空間配置器直接使用malloc()、realloc()、free()函式進行記憶體空間的分配和釋放,而第二級空間配置器採用了記憶體池技術,通過空閒鍊錶來管理記憶體。
這個主要考察的是迭代器失效的問題。
1.對於序列容器vector,deque來說,使用erase(itertor)後,後邊的每個元素的迭代器都會失效,但是後邊每個元素都會往前移動乙個位置,但是erase會返回下乙個有效的迭代器;
2.對於關聯容器map set來說,使用了erase(iterator)後,當前元素的迭代器失效,但是其結構是紅黑樹,刪除當前元素的,不會影響到下乙個元素的迭代器,所以在呼叫erase之前,記錄下乙個元素的迭代器即可。
3.對於list來說,它使用了不連續分配的記憶體,並且它的erase方法也會返回下乙個有效的iterator,因此上面兩種正確的方法都可以使用。
紅黑樹。unordered map底層結構是雜湊表
stl主要由:以下幾部分組成:
他們之間的關係:分配器給容器分配儲存空間,演算法通過迭代器獲取容器中的內容,仿函式可以協助演算法完成各種操作,配接器用來套接適配仿函式
1、map對映,map 的所有元素都是 pair,同時擁有實值(value)和鍵值(key)。pair 的第一元素被視為鍵值,第二元素被視為實值。所有元素都會根據元素的鍵值自動被排序。不允許鍵值重複。
底層實現:紅黑樹
適用場景:有序鍵值對不重複對映
2、multimap
多重對映。multimap 的所有元素都是 pair,同時擁有實值(value)和鍵值(key)。pair 的第一元素被視為鍵值,第二元素被視為實值。所有元素都會根據元素的鍵值自動被排序。允許鍵值重複。
底層實現:紅黑樹
適用場景:有序鍵值對可重複對映
1、概念:
1)vector
連續儲存的容器,動態陣列,在堆上分配空間
底層實現:陣列
兩倍容量增長:
vector 增加(插入)新元素時,如果未超過當時的容量,則還有剩餘空間,那麼直接新增到最後(插入指定位置),然後調整迭代器。
如果沒有剩餘空間了,則會重新配置原有元素個數的兩倍空間,然後將原空間元素通過複製的方式初始化新空間,再向新空間增加元素,最後析構並釋放原空間,之前的迭代器會失效。
效能:訪問:o(1)
插入:在最後插入(空間夠):很快
在最後插入(空間不夠):需要記憶體申請和釋放,以及對之前資料進行拷貝。
在中間插入(空間夠):記憶體拷貝
在中間插入(空間不夠):需要記憶體申請和釋放,以及對之前資料進行拷貝。
刪除:在最後刪除:很快
在中間刪除:記憶體拷貝
適用場景:經常隨機訪問,且不經常對非尾節點進行插入刪除。
2、list
動態鍊錶,在堆上分配空間,每插入乙個元數都會分配空間,每刪除乙個元素都會釋放空間。
底層:雙向鍊錶
效能:訪問:隨機訪問效能很差,只能快速訪問頭尾節點。
插入:很快,一般是常數開銷
刪除:很快,一般是常數開銷
適用場景:經常插入刪除大量資料
2、區別:
1)vector底層實現是陣列;list是雙向 鍊錶。
2)vector支援隨機訪問,list不支援。
3)vector是順序記憶體,list不是。
4)vector在中間節點進行插入刪除會導致記憶體拷貝,list不會。
5)vector一次性分配好記憶體,不夠時才進行2倍擴容;list每次插入新節點都會進行記憶體申請。
6)vector隨機訪問效能好,插入刪除效能差;list隨機訪問效能差,插入刪除效能好。
3、應用
vector擁有一段連續的記憶體空間,因此支援隨機訪問,如果需要高效的隨即訪問,而不在乎插入和刪除的效率,使用vector。
list擁有一段不連續的記憶體空間,如果需要高效的插入和刪除,而不關心隨機訪問,則應使用list。
1、迭代器
iterator(迭代器)模式又稱cursor(游標)模式,用於提供一種方法順序訪問乙個聚合物件中各個元素, 而又不需暴露該物件的內部表示。或者這樣說可能更容易理解:iterator模式是運用於聚合物件的一種模式,通過運用該模式,使得我們可以在不知道物件內部表示的情況下,按照一定順序(由iterator提供的方法)訪問聚合物件中的各個元素。
由於iterator模式的以上特性:與聚合物件耦合,在一定程度上限制了它的廣泛運用,一般僅用於底層聚合支援類,如stl的list、vector、stack等容器類及ostream_iterator等擴充套件iterator。
2、迭代器和指標的區別
迭代器不是指標,是類模板,表現的像指標。他只是模擬了指標的一些功能,通過過載了指標的一些操作符,->、*、++、--等。迭代器封裝了指標,是乙個「可遍歷stl( standard template library)容器內全部或部分元素」的物件, 本質是封裝了原生指標,是指標概念的一種提公升(lift),提供了比指標更高階的行為,相當於一種智慧型指標,他可以根據不同型別的資料結構來實現不同的++,--等操作。
迭代器返回的是物件引用而不是物件的值,所以cout只能輸出迭代器使用*取值後的值而不能直接輸出其自身。
3、迭代器產生原因
iterator類的訪問方式就是把不同集合類的訪問邏輯抽象出來,使得不用暴露集合內部的結構而達到迴圈遍歷集合的效果。
呼叫順序:
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
首先建立乙個epoll物件,然後使用epoll_ctl對這個物件進行操作,把需要監控的描述新增進去,這些描述符將會以epoll_event結構體的形式組成一顆紅黑樹,接著阻塞在epoll_wait,進入大迴圈,當某個fd上有事件發生時,核心將會把其對應的結構體放入到乙個鍊錶中,返回有事件發生的鍊錶。
單調棧
vectorfindmax(vectornum)
else
}while (!s.empty())
for (int i = 0; i < res.size(); i++)
cout << res[i] << endl;
return res;
}
resize():改變當前容器內含有元素的數量(size()),eg:
vectorv;
v.resize(len);
v的size變為len,如果原來v的size小於len,那麼容器新增(len-size)個元素(初始化為0),元素的值為預設為0.當v.push_back(3);之後,則是3是放在了v的末尾,即下標為len,此時容器是size為len+1;
reserve():改變當前容器的最大容量(capacity),它不會生成元素,只是確定這個容器允許放入多少物件,如果reserve(len)的值大於當前的capacity(),那麼會重新分配一塊能存len個物件的空間,然後把之前v.size()個物件通過copy construtor複製過來,銷毀之前的記憶體;
測試**如下:
#include #include using namespace std;
int main()
集合,所有元素都會根據元素的值自動被排序,且不允許重複。
底層實現:紅黑樹
set 底層是通過紅黑樹(rb-tree)來實現的,由於紅黑樹是一種平衡二叉搜尋樹,自動排序的效果很不錯,所以標準的 stl 的 set 即以 rb-tree 為底層機制。又由於 set 所開放的各種操作介面,rb-tree 也都提供了,所以幾乎所有的 set 操作行為,都只有轉呼叫 rb-tree 的操作行為而已。
適用場景:有序不重複集合
2、map
對映。map 的所有元素都是 pair,同時擁有實值(value)和鍵值(key)。pair 的第一元素被視為鍵值,第二元素被視為實值。所有元素都會根據元素的鍵值自動被排序。不允許鍵值重複。
底層:紅黑樹
適用場景:有序鍵值對不重複對映
容器和演算法
在我們編寫每乙個程式時,都會或多或少的需要儲存一些資料,而c 在這方面只提供了幾種最基本的方法,我們可以建立區域性變數或者全域性變數在存放某個值,也可以用陣列來存放多個值。陣列是c 唯一支援的容器,但陣列並不適合用來解決所有的問題 假如我們編寫乙個程式 輸入一串字母,判斷與給定單詞是否一樣。這時候我...
C 容器和演算法
c 容器和演算法 容器部分 順序容器 vector deque list 通過元素在容器中的位置順序儲存和訪問元素 vector 支援快速隨機訪問 容器介面卡為stack後進先出棧 deque 雙端佇列 容器介面卡為priority queue有優先順序管理的佇列 list 支援快速插入 刪除 容器...
C 容器和演算法
1.map和set有什麼區別,分別又是怎麼實現的?2.stl的allocator?c 容器的空間配置器,由兩級分配器構成,大於128位元組,呼叫一級配置器,malloc free,realloc 小於128位元組,預設二級配置器,分配記憶體池。為了便於記憶體管理,減少記憶體碎片產生 3.stl 標準...