本文**
vector是連續記憶體容器,換句話說,標準要求所有標準庫實現的時候,vector中的元素的記憶體必須是連續的。所以對於插入和刪除的時間複雜度是很高的,因為刪除或者插入的時候,需要元素的移動,即元素複製拷貝。
vector的內部實現一般需要用到placement new ,所以效率很高,因為很多的時候,只要我們是使用得到,就可以省去很多的記憶體分配開銷。而且vector的使用,元素可以沒有預設的建構函式,但是需要拷貝建構函式的存在,這是使用carray所無法實現的。
使用原則:
1,盡量使用vector代替c風格的陣列或者carray;
2,盡量使用演算法代替手工寫的迴圈;
3,盡量使用vector本身的函式代替其他泛型演算法;
vector的介面很容易看懂和使用,這裡以一些例子來說明vector的用法。
1,填充vector
如果我們想用原始陣列的內容填充vector,那麼於有很多種方式。我們來一次學習vector的幾個方法。
例如我們有陣列int v1[10] = ;
初始化方式1:
vectorv2(10); //初始化size為10可以避免陣列動態增長的時候不斷的分配記憶體
//v2.reserve(10);//同上,只要使用其中乙個就可以了
for( int i=0; i<10; i++ )
初始化方式2:
vectorv3(&v1[0],&v1[9]);//原始陣列的元素指標可以作為迭代器來使用
初始化方式3:
vectorv4;
v4.reserve(10);
v4.insert(v4.begin(), &v1[0], &v[9]);
初始化方式4:
vectorv5(10);
copy(v5.begin(), &v1[0], &v1[9]);
原始陣列的元素指標可以作為迭代器來使用。
原則:盡量使用reserve來減少不必要的記憶體分配次數。
原則:盡量使用empty而不是size()==0 來判斷容器是否為空
有可能我們需要在vector中插入相應的元素
vector::iterator i = find( v1.begin(), v1.end(), 3);
if( i != v1.end() )
2,遍歷vector
例如有vectorv1;
void print( int i)
方式1:
for( int i=0; i
這種方式是我們最熟悉的,但是不夠好,寫起來不夠簡潔。而且對於沒有隨機迭代器的其他容器來說,這樣做是辦不到的。
方式2:
typedef vector:: iterator vintiterator;
vintiterator end = v1.begin();
for( vintiterator i=v1.begin(); i != end; ++i )
注意:先計算end有好處,因為不必要每次去重複計算end,vector的end()不是常數時間的,所以先快取下來能提高效率。寫演算法的時候盡量使用!=比較迭代器,因為《對於很多非隨機迭代器沒有這個操作符。
但是這種方式也寫起來比較繁瑣。
方式3:
for_each( v1.begin(), v1.end(), print );
使用演算法寫起來簡單多了。
使用演算法的時候,可以使用函式物件,例如
class output
} for_each( v1.begin(), v1.end(), output );
3,vector中的刪除
刪除指定元素
vectorv1;
//….初始化**
vector:: iterator i = find( v1.begin(), v1.end(), 3.0 );
if( i != v1.end() )
這樣就真的刪除了麼指定的元素了麼?沒有。其實只是內部的元素作了移動,vector的刪除的時間複雜度是很高的。所以選擇容器的時候,如果需要頻繁在中間插入和刪除元素,那選擇vector就會影響效率了。
注意:插入或者刪除操作會使得迭代器失效。
原則:使用erase-remove慣用法刪除元素
v1.erase( remove(v1.begin(), v1.end(), 3.0), v1.end() );
4,vector是否為空
在判斷容器是否為空的時候,使用empty()來代替size()是否為了0的檢查方式,因為empty更加高效時間複雜度是常數時間的,size()時間複雜度不是常數時間的。
原則:使用empty判斷標準容器是否為空
5,vector中的查詢
原則:盡量使用標準容器自帶的演算法代替公共演算法。
但是vector中並沒有多少自己的演算法,倒是list中有remove ,remove_if,sort,reverse等演算法。
find
find_if
6,使用交換技巧來修正過剩的容量
vectorv1;
//…初始化v1
//…刪除v1中所有的元素
但是這個時候v1的記憶體容量並不是0,還是很大的一塊記憶體沒有釋放,如果想清空
用v1.reserve(0);到不到目標,因為reserve只能擴大記憶體容量,並不能減小。
vectorv2;
v2.swap(v1);
這個時候就是真的將之記憶體容量降到最低了。
6,題外話:使用演算法及其他技巧
原則:不要使用auto_ptr作為模板引數來建立容器,這會產生意想不到的陷阱,因為auto_ptr的拷貝有特殊的語義
原則:避免使用vector, 因為它不能當作標準容器來用
copy
find_if
for_each
原則:盡量使用區間成員函式代替它們的單元素引數兄弟成員函式
區間構造
區間刪除
區間賦值
區間插入
原則:使得容器中元素的拷貝操作輕量而正確,拷貝是stl中容器的執行的基本方式,將元素加入到容器,必然保持乙個拷貝,容器中的元素不再是原來的那個元素,所以如果將指標加入容器,必須在容器離開作用域以前刪除指標所指的物件。
void fun()
}
原則:注意對於 vector,任何插入刪除操作都會引起迭代器失效。所以要小心。
第二部分 使用錯誤討論
vector的語義常被誤解,所以經常會出現使用錯誤
1,案例一
你能發現下面的問題所在麼?
void func( vector<.int>& v1 )
#1和#2有何區別?
void func1( vector& v1 )
cout << v1[0];
v1.reserve(100);
assert(v1.capicity() == 100 );
cout << v1[0];
v1[2] = 3;
v1[3] = 4;
//……
v[99] = 100;
for( vector::iterator i = v1.begin(); i
} 函式func1存在什麼問題(叢風格和**正確性做出評價)?會列印出什麼?
2,案例二
使用vector的時候最容易發生的執行時錯誤,莫過於迭代器錯誤
注意:對於 vector,任何插入刪除操作都會引起迭代器失效。所以要小心
STL之vector使用詳解
好久不用stl了,忘的差不多了,總結一下vector的使用方式,就不對每個方法做出詳細解釋了,只給出了如何用 void testvector 構造乙個元素值全為2大小為10的vector vectorv1 10,2 用指標構造 vectorv2 a,a 10 用vector iterator構造 v...
STL之使用vector排序
應用場景 在記憶體中維持乙個有序的vector 1 2 3 include 4 include 5 include 67 先自定義乙個結構體 8struct test 13bool sortbym1 const test v1,const test v2 注意 本函式的引數的型別一定要與vector...
教你使用STL容器之vector
c 語言本身提供了乙個序列式容器array,stl另外再提供vector list deque stack queue priority queue等序列式容器。vector的資料安排以及操作方式,與array是很相似的,唯一的不同點在於空間的運用的靈活性,array是靜態的,一旦配置了就不能再改變...