C++從序列容器中刪除元素的四種方法
一、簡介
本文討論從集合中刪除元素的STL算法。從C++集合中刪除一個(gè)元素可能不復(fù)雜,也可能有點(diǎn)復(fù)雜。
刪除元素的方法在序列容器和關(guān)聯(lián)容器之間是非常不同的。在序列容器中,vector
和 string
是最常用的。但這里也會(huì)介紹 deque
和 list
以供全面了解,盡管在一般情況下可能不會(huì)使用它們。
至少有四種方法可以指定從任何容器中刪除哪些值:
- 在給定位置(或在兩個(gè)給定位置之間)刪除元素;
- 刪除等于某個(gè)值的元素;
- 刪除滿足某個(gè)謂詞的元素
- 以及刪除重復(fù)項(xiàng)。
下面來看看如何在STL序列容器中實(shí)現(xiàn)這四種命令。
二、移除給定位置的元素
這是最簡單的方法。如果是一個(gè)序列容器,可以通過調(diào)用erase
。比如:
c.erase(position);
要移除由迭代器first
和last
組成的子范圍中的元素,可以這么調(diào)用:
c.erase(first, last);
與STL中迭代器表示的所有范圍一樣,子范圍包括first,而不包括last。last指向“past-the-end”元素,類似于容器的結(jié)束迭代器。
注意,對于vector和string,所有指向被移除對象所在位置和之后元素的迭代器都無效。因?yàn)樗羞@些元素都被erase函數(shù)調(diào)用移除了。
對于deque來說,會(huì)有一點(diǎn)點(diǎn)不同:參考cppreference.com,所有迭代器和引用都無效,除非被刪除的元素位于容器的末尾或開頭,在這種情況下,只有迭代器和對被刪除元素的引用無效。
- 如果刪除的元素位于
deque
的中間位置,則所有指向該元素以及之后位置的迭代器和引用都會(huì)失效。 - 如果刪除的是末尾元素,那么僅僅指向這個(gè)末尾元素的迭代器和引用會(huì)失效,其余保持有效。
- 如果刪除的是開頭元素,同樣只有指向這個(gè)開頭元素的迭代器和引用會(huì)失效。
這erase
很簡單,只是熱身。下面還有復(fù)雜的,接著閱讀學(xué)習(xí)吧。
三、移除與某個(gè)值相等的元素
3.1、序列容器vector、deque、string
這些容器沒有刪除值的方法,因此需要使用std::remove
算法。該算法取一個(gè)要?jiǎng)h除的范圍和一個(gè)值,并上移所有要保留的元素。
例如,在這個(gè)整數(shù)范圍內(nèi)調(diào)用std::remove
并帶值42,會(huì)有以下行為:
注意,在范圍末尾剩下的元素的值是未指定的。盡管有些實(shí)現(xiàn)可以將最初位于集合末尾的元素保留下來,但這是不可靠的。
要記住,在STL的設(shè)計(jì)中,算法只與迭代器交互,而不直接與容器交互,因此容器并不知道算法的效果。例如,它的size并沒有縮小。
為了有效地從集合中刪除元素,需要使用在本文前面講到的erase方法。為此,要注意到std::remove返回一個(gè)迭代器,該迭代器指向不應(yīng)被刪除的元素范圍內(nèi)的“past-the-end”元素。即,要?jiǎng)h除的元素位于std::remove返回的迭代器定義的范圍和集合的末尾。
因此,要有效地從vector、deque或string對象中刪除值,可以這樣寫:
v.erase(std::remove(begin(v), end(v), 42), end(v));
3.2、封裝成模板方法
這是C++的習(xí)慣用法,如果在代碼中遇到它,必須知道。但是,坦白地講,不覺得用這么多代碼來表達(dá)這么簡單的事情有點(diǎn)多嗎?難道不喜歡像下面這樣寫嗎?
v.remove(42); // or v.erase(42);
也可以給它添加一些重載來操作deque和string對象:
template<typename T> void erase(std::deque<T>& deque, T const& value) { deque.erase(std::remove(begin(deque), end(deque), value), end(deque)); } void erase(std::string& string, char letter) { string.erase(std::remove(begin(string), end(string), letter), end(string)); }
非常建議實(shí)現(xiàn)這些輔助函數(shù),特別是對于最常用的vector
。這可以避免標(biāo)準(zhǔn)習(xí)慣用法所帶來的迭代器的糾纏。
甚至在C++標(biāo)準(zhǔn)中,就有學(xué)者提出了一個(gè)增加這種泛型函數(shù)的建議。很遺憾的是,它還沒有在C++ 17中實(shí)現(xiàn)。
3.3、list的remove成員函數(shù)
為了全面起見,這里提一下要從list
中刪除一個(gè)元素,有一個(gè)叫做remove
的方法,例如:
l.remove(42);
由于它不提供隨機(jī)訪問迭代器,在列表上使用std::remove
算法會(huì)使列表變得比現(xiàn)在更慢。
四、刪除滿足謂詞的元素
前面已經(jīng)看到了如何從序列容器中刪除所有等于某個(gè)值的元素,比如42。那么,如何移除滿足謂詞func
的元素?其實(shí),這完全一樣,只是需要使用 remove_if
而不是 remove
。
所以只需要替換:
remove
為remove_if
;- 42為
func
。
std::remove_if(begin(string), end(string), func)
和上一節(jié)一樣。依然建議編寫一個(gè)名為erase_if
的自由函數(shù),以避免大量迭代器的出現(xiàn);并且list
同樣有一個(gè)名為remove_if
的成員方法。因此,為了遵循“不要重復(fù)”的原則和避免文章篇幅過長,這里不再對remove_if
進(jìn)行更多討論。
五、從序列容器中刪除重復(fù)項(xiàng)
從序列容器中刪除重復(fù)項(xiàng)的STL算法是std::unique。但是要注意!unique只刪除相鄰的重復(fù)項(xiàng),而不刪除整個(gè)集合中的重復(fù)項(xiàng)。它具有線性復(fù)雜度。
除此之外,unique和remove非常相似。它只壓縮集合的元素,而不能改變?nèi)萜鞅旧韘ize。因此,需要在容器上調(diào)用erase才能有效地刪除重復(fù)項(xiàng):
vector.erase(std::unique(begin(v), end(v)), end(v));
和remove
一樣,封裝一個(gè)方便的函數(shù)是必要的:
template<typename T> void unique(std::vector<T>& vector) { vector.erase(std::unique(begin(vector), end(vector)), end(vector)); } template<typename T> void unique(std::deque<T>& deque) { deque.erase(std::unique(begin(deque), end(deque)), end(deque)); } void unique(std::string& string) { string.erase(std::unique(begin(string), end(string)), end(string)); }
與remove
類似,std::list
有一個(gè)unique
的成員方法。
六、總結(jié)
這就是C++中從序列容器中刪除元素的方法。
在C++中,從序列容器中刪除元素的方法多種多樣,每種方法都有其適用的場景和使用方式。
移除給定位置的元素:可以使用
erase
方法,通過指定要?jiǎng)h除的元素位置或者給定范圍的迭代器來實(shí)現(xiàn)。移除與某個(gè)值相等的元素:對于
vector
、deque
和string
等序列容器,可以使用std::remove
算法,并結(jié)合erase
方法來刪除指定值的元素;或者封裝成模板函數(shù)來簡化操作。刪除滿足謂詞的元素:使用
std::remove_if
算法結(jié)合erase
方法,可以刪除滿足指定謂詞條件的元素。從序列容器中刪除重復(fù)項(xiàng):利用
std::unique
算法可以刪除相鄰的重復(fù)項(xiàng),但需要注意該算法只刪除相鄰的重復(fù)項(xiàng),并且不能改變?nèi)萜鞯拇笮。枰浜?code>erase方法來實(shí)現(xiàn)刪除整個(gè)容器中的重復(fù)項(xiàng)。
以上就是C++從序列容器中刪除元素的四種方法的詳細(xì)內(nèi)容,更多關(guān)于C++序列容器刪除元素的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語言實(shí)現(xiàn)動(dòng)態(tài)開辟存儲(chǔ)楊輝三角
這篇文章主要介紹了如何利用C語言實(shí)現(xiàn)動(dòng)態(tài)開辟存儲(chǔ)楊輝三角,可以靈活的開辟空間,充分的利用空間。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2022-03-03在QT5中實(shí)現(xiàn)求兩個(gè)輸入值的和并輸出(實(shí)例)
下面小編就為大家?guī)硪黄赒T5中實(shí)現(xiàn)求兩個(gè)輸入值的和并輸出(實(shí)例)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08C++生成隨機(jī)浮點(diǎn)數(shù)的示例代碼
在C++11之前,我們通常采用rand函數(shù)來生成隨機(jī)數(shù),但rand函數(shù)對一些情況顯得難以處理。本文將介紹如何利用C++生成隨機(jī)浮點(diǎn)數(shù),需要的可以參考一下2022-04-04一篇文章帶你用C語言玩轉(zhuǎn)結(jié)構(gòu)體
本文主要介紹C語言 結(jié)構(gòu)體的知識,學(xué)習(xí)C語言肯定需要學(xué)習(xí)結(jié)構(gòu)體,這里詳細(xì)說明了結(jié)構(gòu)體并附示例代碼,供大家參考學(xué)習(xí),有需要的小伙伴可以參考下2021-09-09