怎麼從vector裡刪除元素

2021-05-25 03:14:01 字數 3911 閱讀 4024

現在用stl的人越來越多, stl確實是套很漂亮的演算法和資料結構庫. 但是初用stl的人往往會遇上很多問題.

從乙個容器中刪除元素,是很常用的操作,但是也是初學者常會犯錯誤的地方,刪除map和list中元素可能會犯迭代器失效的錯誤. vector是stl裡很常用的乙個容器, 和map,list等容器相比, 從vector中刪符合某些條件的元素有更多的麻煩.

比如,我們要完成如下的任務.

有下面的類

class  aa

aa( int  b):n(b){}

int  n;};

有個vector

vectorvaa;

乙個list

listintlist;

現在需要執行這樣的操作, 刪除vaa裡所有成員變數n在intlist裡的所有元素.那麼, 應該怎麼做呢?我們可以有下列選擇:

1 手寫迴圈

仿照list的刪除方法.

vector < aa > ::iterator ite  =  vaa.begin();

for  (; ite  !=  vaa.end(); )

一執行就會發現不行了, vector的erase的特點是, 被刪除的元素和之後的所有元素的iterator都失效了, 即使儲存了後面乙個iterator, 也不能繼續遍歷了. 對於這種連續儲存的序列, 應該是把不需要的元素用需要的代替, 然後把結尾不要的元素刪除.像這樣:

vector < aa > ::iterator ite  =  vaa.begin();

vector < aa > ::iterator dest  =  ite;

for (; ite  !=  vaa.end();  ++ ite)

}vaa.erase(dest, vaa.end()); 

2. 使用remove_if, 寫乙個判斷函式作為條件.

像上面那樣寫迴圈,麻煩,容易錯而且不好讀, stl提供了乙個演算法remove_if可以不用自己寫迴圈,完成上面那個迴圈的功能, 就是把不要的

元素用需要的元素代替, 返回結尾處的iterator.remove_if的原型為

template  < class  forwarditerator,  class  predicate >

forwarditerator remove_if(forwarditerator first, forwarditerator last,predicate pred); 

pred是乙個函式子,用來作為判斷條件. 函式子是可以按照函式呼叫的語法來使用的型別, 它可以是乙個函式指標, 也可以是乙個過載了operator()的型別.這裡pred要求是返回值是bool,有乙個引數的函式子, 引數型別就是容器裡元素的型別, 對每個元素執行這個函式, 返回true就會被remove.

所以,我們需要先寫乙個函式來判斷乙個aa型別的變數是否滿足條件. 但是, 這個函式顯然需要兩個引數, 乙個aa 和乙個list,為了避免拷貝,我們用指標傳遞list

bool  inthelist( aa aa,  const  list < int >   * lint)

要把這個兩個引數的函式繫結上乙個引數變成乙個引數的函式, 可以使用stl裡的bind2nd函式,原型如下

template  < class  adaptablebinaryfunction,  class  t >

binder2nd < adaptablebinaryfunction > 

bind2nd( const  adaptablebinaryfunction &  f,  const  t &  c); 

這個函式並不會被執行, 編譯器只是靠它來做型別推導, 它會返回乙個adaptable unary function 型別. 它的第乙個引數是乙個adaptable binary function, 它是乙個重定義了operator()的型別,不能直接傳乙個函式指標, 所以我們需要ptr_fun函式,ptr_fun對雙參函式指標的過載的原型為:

template  < class  arg1,  class  arg2,  class  result >

pointer_to_binary_function < arg1, arg2, result > 

ptr_fun(result ( * x)(arg1, arg2)); 

這個函式也是用來做型別推導的, 可以返回乙個adaptable unary function.

綜合以上各個函式, 於是就可以這樣寫了:

vaa.erase(remove_if(vaa.begin(), vaa.end(),bind2nd(ptr_fun(inthelist), & intlist)), vaa.end()); 

注意, 可能是vc6的bug, 如果inlist是乙個類的靜態成員函式, 上面的寫法在vc6裡無法編譯, vc6不能推導出函式子的型別,上面的寫法在vc8和gcc中是可以的.對於vc6,需要顯式的告訴編譯器我們傳的是函式指標,像下面這樣

vaa.erase(remove_if(vaa.begin(), vaa.end(),bind2nd(ptr_fun( & inthelist), & intlist)), vaa.end()); 

我們也可以讓inthelist是aa的乙個成員函式

bool  aa::inthelist( const  list < int >   * lint) 

stl提供了一套把成員函式轉為單參或雙參函式子的函式,mem_fun1_ref,這裡我們用上面的刪除操作就可以寫成:

vaa.erase(remove_if(vaa.begin(), vaa.end(),bind2nd(mem_fun1_ref( & aa::inthelist), & intlist)), vaa.end()); 

3, 還是用remove_if, 自己定義判斷條件的函式子型別

上面那套轉換和繫結肯定能讓人抓狂, 使用函式指標來傳遞判斷條件也比較低效. 我們可以自己定義乙個型別

class  inlistfunctor

bool   operator  ()(aa a)

private :

const  list < int >   & m_list;

} ; 

這樣就可以直接傳給remove_if了, inlistfunctor的建構函式接受乙個list的const引用, 可以把要比較的list傳進去.

vaa.erase(remove_if(vaa.begin(), vaa.end(), inlistfunctor(intlist)), vaa.end()); 

通過自己定義的函式子,可以構造很複雜的比較條件,更加方便和自由.

4, 用boost::lambda, 構造匿名函式.

上面兩個方法都有個共同的缺點, 要麼要定義乙個函式, 要麼要定義乙個型別, 這都會給乙個類裡新增不必要的東西,這在實際程式設計中會讓人覺得不爽. c++0x 裡面提供了 lambda ,可以構造匿名函式。這個特性已經在 vs2010 裡面實現了。於是可以用下面的**來實現刪除。

vaa.erase(remove_if(vaa.begin(), vaa.end(),

[&intlist](const aa &a)),

vaa.end());

刪除所有偶數項,並列印出刪除的項

1. vector/queue

正確方法1:

void

erase(vector

<

int>&v)

else

++vi;}}

正確方法2:

void

erase2(vector

<

int>&v)

else

++ri;}}

2.map/list

正確方法

void

erase(map

<

int,

int>&m)

else

++mi;}}

怎麼從vector裡刪除元素

現在用stl的人越來越多,stl確實是套很漂亮的演算法和資料結構庫.但是初用stl的人往往會遇上很多問題.從乙個容器中刪除元素,是很常用的操作,但是也是初學者常會犯錯誤的地方,刪除map和list中元素可能會犯迭代器失效的錯誤.vector是stl裡很常用的乙個容器,和map,list等容器相比,從...

Vector容器刪除元素

使用vector容器也有一段時間了,但是對於他的刪除操作還是有點疑問,今天就總結一下。vector資料儲存是一段預先分配好大小的記憶體連續的空間,插入資料和刪除資料都會引起後面資料記憶體的整體移動。今天就說說刪除操作吧 1 刪除最後的元素 直接使用pop back 就可以了,這個沒什麼好說的 2 刪...

vector 之刪除元素

刪除指定位置的元素 刪除vector中第5個位置的元素 1 vector vec 執行vector初始化操作 2 vector iterator iter vec.begin 5 獲取第五個元素的iterator 3 vec.erase iter 刪除第五個元素 刪除重複元素 刪除vector中的重...