在應用中,咱們一般不可避免地要對容器中的某些特定元素進行刪除操做。這看起來並非什麼困難的問題。咱們先寫一個循環來迭代容器中的元素,若是迭代元素是要刪除的元素,則刪除之。代碼以下所示:算法
- vector<int> intContainer;
-
- for(vector<int>::iterator is = intContainer.begin(); it != intContainer.end(); ++it)
- {
- if ( *it == 25)
- intContainer.erase(it);
- }
vector<int> intContainer; for(vector<int>::iterator is = intContainer.begin(); it != intContainer.end(); ++it) { if ( *it == 25) intContainer.erase(it); }
寫出此代碼的原意是將vector中值爲25的元素刪除,但不幸的是,這樣作是錯誤的,這麼作會帶來詭異的未定義行爲。由於當一個容器的一個元素被刪除時,指向那個元素的全部迭代器將失效。當intContainer.erase(it)返回時,it已經失效。在for循環中對於失效的it執行自增操做,這是一件多麼不靠譜的事情啊。
既然這樣行不通,那麼咱們能夠求助於STL提供的remove算法。藉助remove算法來達到刪除元素的目的。函數
- vector<int> intContainer;
-
- size_t before_size = intContainer.size();
- remove(intContainer.begin(), intContainer.end(), 25);
- size_t after_size = intContainer.size();<span style="font-family:'Times New Roman';font-size:18px;">
- </span>
vector<int> intContainer; size_t before_size = intContainer.size(); remove(intContainer.begin(), intContainer.end(), 25); size_t after_size = intContainer.size();<span style="font-family:'Times New Roman';font-size:18px;"> </span>
運行程序之後發現before_size和after_size是同樣的,說明元素並無被真正刪除。寫出以上程序,是處於對remove算法的不瞭解而致。STL中remove算法會將不應刪除的元素前移,而後返回一個迭代器,該迭代器指向的是那個應該刪除的元素,僅此而已。因此若是要真正刪除這一元素,在調用remove以後還必須調用erase,這就是STL容器元素刪除的"erase_remove"的慣用法。
- vector<int> intContainer;
-
- intContainer.erase( remove(intContainer.begin(), intContainer.end(), 25), intContainer.end());<span style="font-family:'Times New Roman';font-size:18px;">
- </span>
vector<int> intContainer; intContainer.erase( remove(intContainer.begin(), intContainer.end(), 25), intContainer.end());<span style="font-family:'Times New Roman';font-size:18px;"> </span>
erase-remove的慣用法適用於連續內存容器,好比vector,deque和string,它也一樣適用於list,可是並非咱們推薦的方法,由於使用list成員函數remove會更高效,代碼以下:spa
- list<int> list_int;
- ....
- list_int.remove(25);
list<int> list_int; .... list_int.remove(25);
若是是關聯容器呢?標準關聯容器沒有remove成員函數,使用STL算法的remove函數時編譯同不過。因此上述remove形式對於標準關聯容器並不適用。在這種狀況下,解決辦法就是調用erase:
- map<int, int> mapContainer;
- ...
- mapContainer.erase(25);
map<int, int> mapContainer; ... mapContainer.erase(25);
對於標準關聯容器,這樣的元素刪除方式是簡單有效的,時間複雜度爲O(logn).
當咱們須要刪除的不是某一個元素,而是具有某一條件的元素的時候,咱們只須要將remove替換成remove_if便可
.net
- bool Is2BeRemove(int value)
- {
- return value < 25;
- }
- vector<int> nVec;
- list<int> nList;
- ....
-
- nVec.erase(remove_if(nVec.begin(), nVec.end(), Is2BeRemove), nVec.end());
- nList.remove_if(Is2BeRemove);<span style="font-family:'Times New Roman';font-size:18px;">
- </span>
bool Is2BeRemove(int value) { return value < 25; } vector<int> nVec; list<int> nList; .... nVec.erase(remove_if(nVec.begin(), nVec.end(), Is2BeRemove), nVec.end()); nList.remove_if(Is2BeRemove);<span style="font-family:'Times New Roman';font-size:18px;"> </span>
總結以下
刪除容器中具備特定值的元素:blog
若是容器是ector、string或者deque,使用erase-remove的慣用法。若是容器是list,使用list::remove。若是容器是標準關聯容器,使用它的erase成員函數。內存
刪除容器中知足某些條件的元素:rem