vector的 陣列 用法陷阱

2021-08-18 17:15:22 字數 3331 閱讀 6317

vector類為內建陣列提供了一種替代表示,與string類一樣 vector 類是隨標準 c++引入的標準庫的一部分 ,為了使用vector 我們必須包含相關的標頭檔案  :

#include

使用vector有兩種不同的形式,即所謂的陣列習慣和 stl習慣。

1. 定義乙個已知長度的 vector :

vector< int > ivec( 10 );  //類似陣列定義int ia[ 10 ];

可以通過ivec[索引號] 來訪問元素

使用 if ( ivec.empty() ) 判斷是否是空,ivec.size()判斷元素個數。

2. vector的元素被初始化為與其型別相關的預設值:算術和指標型別的預設值是 0,對於class 型別,預設值可通過呼叫這類的預設建構函式獲得,我們還可以為每個元素提供乙個顯式的初始值來完成初始化,例如  

vector< int > ivec( 10, -1 ); 

定義了 ivec 它包含十個int型的元素 每個元素都被初始化為-1 

對於內建陣列 我們可以顯式地把陣列的元素初始化為一組常量值,例如 : 

int ia[ 6 ] = ;

我們不能用同樣的方法顯式地初始化 vector ,但是可以將 vector 初始化為乙個已有陣列的全部或一部分,只需指定希望被用來初始化 vector 的陣列的開始位址以及陣列最末元的下一位置來實現,例如:  

// 把 ia 的 6 個元素拷貝到 ivec 中 

vector< int > ivec( ia, ia+6 );

被傳遞給ivec 的兩個指標標記了用來初始化物件的值的範圍,第二個指標總是指向要拷貝的末元素的下一位置,標記出來的元素範圍也可以是陣列的乙個子集,例如 :

// 拷貝 3 個元素 ia[2], ia[3], ia[4] 

vector< int > ivec( &ia[ 2 ], &ia[ 5 ] );

3. 與內建陣列不同 vector 可以被另乙個 vector 初始化 或被賦給另乙個 vector 例如  

vector< string > svec; 

void init_and_assign() 

在 stl9中對vector 的習慣用法完全不同。我們不是定義乙個已知大小的 vector,而是定義乙個空 vector  

vector< string > text;

1. 我們向 vector 中插入元素,而不再是索引元素,以及向元素賦值,例如 push_back()操作,就是在 vector 的後面插入乙個元素下面的 while 迴圈從標準輸入讀入乙個字串序列並每次將乙個字串插入到 vector 中  

string word; 

while ( cin >> word )

雖然我們仍可以用下標操作符來迭代訪問元素  

cout << "words read are: \n"; 

for ( int ix = 0; ix < text.size(); ++ix ) 

cout << text[ ix ] << ' '; 

cout << endl; 

但是 更典型的做法是使用 vector 操作集中的begin()和 end()所返回的迭代器 iterator

對 :cout << "words read are: \n"; 

for ( vector::iterator it = text.begin(); 

it != text.end(); ++it ) 

cout << *it << ' '; 

cout << endl 

iterator 是標準庫中的類,它具有指標的功能 

*it; 

對迭代器解引用,並訪問其指向的實際物件  

++it;

向前移動迭代器 it 使其指向下乙個元素  

2. 注意 不要混用這兩種習慣用法, 例如,下面的定義  

vector< int > ivec; 

定義了乙個空vector 再寫這樣的語句  

ivec[ 0 ] = 1024; 

就是錯誤的 ,因為 ivec 還沒有第乙個元素,我們只能索引 vector 中已經存在的元素 size()操作返回 vector 包含的元素的個數 。

3. 類似地 當我們用乙個給定的大小定義乙個 vector 時,例如  :

vectoria( 10 );

任何乙個插入操作都將增加vector 的大小,而不是覆蓋掉某個現有的元素,這看起來好像是很顯然的,但是 下面的錯誤在初學者中並不少見 :

const int size = 7; 

int ia[ size ] = ; 

vector< int > ivec( size ); 

for ( int ix = 0; ix < size; ++ix ) 

ivec.push_back( ia[ ix ]); 

程式結束時ivec 包含 14 個元素, ia 的元素從第八個元素開始插入

深入理解

在向量中,所有元素都是連續儲存的。也就是說,不僅可以通過迭代器(iterators)訪問各個元素,也可以通過指向元素的指標加上偏移來訪問。還意味著,當向任意函式傳遞向量的乙個元素的指標時,這個指標可以直接被認為指向了乙個陣列中的某個元素。

向量內部的儲存調整是自動處理的,按需擴充套件或壓縮。通常,相比靜態陣列(static arrays),向量將會占用更多的儲存空間,因為額外的記憶體將被未來增長的部分所使用。就因為這點,當插入元素時,向量不需要太頻繁地重分配(reallocate)記憶體。當前最大容量可以通過函式 capacity() 查詢。額外的記憶體可以通過呼叫 shrink_to_fit() 函式返還給作業系統。

當增加向量物件中的序列的長度時,如果超出當前儲存容量上限,就會發生記憶體重分配(reallocation),即內部將會重新分配乙個陣列,然後按順序逐個拷貝元素。其它的插入及刪除操作將會修改序列中部分元素的記憶體位址。在上述所有情況下,指向序列中被修改部分的迭代器或引用將會失效。當未發生記憶體重分配,僅指向插入或刪除點之前元素的迭代器或引用才會保持有效性。

標準庫可以執行不同的增長策略來平衡記憶體的使用量與重分配所耗的效能。但不管哪種情況下,重分配記憶體的大小必須以指數方式增長,只有這樣,才能將在向量末尾逐個插入元素所需的時間複雜度整體分攤(amortized)為乙個恆定值。

記憶體重分配就效能而言是乙個高代價操作。如果在使用向量前知道元素的數量,可以通過 reserve() 消除記憶體重分配。

向量支援在序列末尾恆定耗時的插入及刪除元素。而在向量的中間插入或刪除元素則需要線性的時間。在只涉及向序列起始或未尾插入及刪除元素操作時,std::deque​ 容器的效能將會高出很多。當涉及向序列中的任意位置進行插入及刪除操作時,std::list 容器的效能將會高出很多。

常用操作的演算法複雜度(效能相關)如下:

Vector 不定長陣列基礎用法

好久沒寫了呢,markdown的用法都忘得七七八八了。今天在看網路流的問題,挑戰上的演算法設計vector 之前就沒看懂,這次稍微統計一下用法,一些基礎方法什麼的 在c 中,vector是乙個十分有用的容器,下面對這個容器做一下總結。1 基本操作 1 標頭檔案 include.2 建立vector物...

C 之 Vector陣列基礎用法介紹

目錄前言 一 vector陣列簡介 1 引入 2 vector陣列概念 二 vector陣列用法 1 陣列的初始化 1.建構函式 2.常用初始化方式 示例 3.通過insert初始化 2 vector的用法 3 vector的演算法 在寫c 的時候,經常會遇到vector陣列,特別是在學習openc...

vector的高階用法

這裡主要介紹vector的元素訪問方法,迭代器相關函式,元素查詢和搜尋,字串排序,插入元素,刪除元素,交換元素等內容。1 元素訪問方法 按c和c 的慣例,第乙個元素的下標為0 最後乙個元素的索引下標為size 1,即第n個元素的下標為n 1。可以直接訪問vector型容器中元素的操作方法主要包括 a...