1.引言
以下代碼有什麼問題,如何修改?
- #include<iostream>
- #include<vector>
- using namespace std;
- void print(vector<int>);//傳引用不妥!!
- int main()
- {
- vector<int> array;
- array.push_back(1);
- array.push_back(6);
- array.push_back(6);
- array.push_back(3);
- //刪除array中的所有的6
- vector<int>::iterator itor;
- vector<int>::iterator itor2;
- itor=array.begin();
- for (itor=array.begin();itor!=array.end();itor++;)
- {
- if (6==*itor)
- {
- itor2=itor;
- array.erase(itor2);
- }
- }
- print(array);
- return 0;
- }
- void print(vector<int> v)
- {
- cout<<"\nvector size is: "<<v.size()<<endl;
- }
2.vector中erase源碼
這段代碼運行後容量只減小1,具體問題出在哪不知道。先看一下erase的源碼。
- iterator erase(iterator position)
- {
- if (position + 1 != end()) //若position不是指向最後一個元素
- copy(position + 1, finish, position); //運用的是copy,將刪除位置的元素向後移動
- --finish;//vector中finish所指位置爲end()返回值
- destroy(finish);
- return position;
- }
- iterator erase(iterator first, iterator last) //允許last在first之前,後果自負
- {
- iterator i = copy(last, finish, first);
- destroy(i, finish);
- finish = finish - (last - first);
- return first;
- }
現在知道了,如果這時刪除一個元素之後,itor已經指向下一個元素,所以再調用itor++,那麼連續的2個6就只能刪除前一個。
所以以上的for循環可以改爲:
- for (itor=array.begin();itor!=array.end();itor++;)
- {
- if (6==*itor)
- {
- itor2=itor;
- array.erase(itor2);
- itor--;
- }
- }
3.remove源碼
但是這樣的代碼可讀性欠佳,還有一種改法就是更加規範的簡潔的操作:調用算法remove,之後再進行erase。
此時將for循環替代爲:array.erase(remove(array.begin().array.end(),6),array.end());當然這個時候要包含頭文件<algorithm>。
爲什麼要刪除,remove返回後的迭代器到vector末尾的元素呢?看remove算法源碼。
remove操作移除[first,last)之中所有與value相等的元素。這一算法並不真正從容器中刪除那些元素(換句話說容器的大小並沒有改變),而是將每一個不與value相等的元素輪番賦值給first之後的空間。返回值ForwardIterator標示出重新整理後的最後元素的下一個位置。例如序列{0,1,0,2,0,3,0,4},如果執行remove刪除0,則結果是{1,2,3,4,0,3,0,4},返回值ForwardIterator指向第5個元素。所以如果要刪除那些殘餘元素可以使用erase的兩迭代器版本。源碼如下:
- tamplate<class ForwardIterator, class T>
- ForwardIterator remove(ForwardIterator first, ForwardIterator last, const T& value)
- {
- first=find(first, last, value);//找到第一個相等的元素
- ForwardIterator next = first;//以next標示出來
- //以下利用“remove_copy()允許新舊容器重疊”的性質,進行移除操作
- //並將結果置於原容器中
- return first == last ? first : remove_copy(++next,last,first,value);
- }
remove_copy並不改變原來的容器,只是將所要刪除的值刪除後,將新容器存儲在result迭代器所指的位置處。
- tamplate<class InputIterator, class OutputIterator, class T>
- OutputIterator remove_copy(InputIterator first, InputIterator last, OutputIterator result, const T& value)
- {
- for(;first != last;++first)
- if(*first != value) //如果不相等
- {
- *result = *first; //賦值給新容器
- ++result;
- }
- return result;
- }
當然remove函數也有仿函數版本的remove_if,remove_copy_if。
4.list中的remove和erase操作
list中的erase:
- iterator erase(iterator position)
- {
- link_type next_node = link_typr(position.node->next);
- link_type prev_node = link_typr(position.node->prev);
- prev_node->next = next_node;
- next_node->prev = prev_node;
- destroy_node(position.node);
- return iterator(next_node);
- }
remove是算法庫中的一個算法,但是list的結構使用這種remove算法時效率低下。根據list的結構,標準庫專門爲list設計了remove操作(其他容器是沒有的)。
- template<class T, calss Alloc>
- void list<T,Alloc>::remove(const T& value)
- {
- iterator first = begin();
- iterator last = end();
- while(first != last)
- {
- iterator next = first;
- ++next;
- if(*first == value)