概述
C++內置的數組支持容器的機制,但是它不支持容器抽象的語義。要解決此問題我們自己實現這樣的類。在標准C++中,用容器向量(vector)實現。
容器向量也是一個類模板。vector是C++標准模板庫中的部分內容,它是一個多功能的,能夠操作多種數據結構和算法的模板類和函數庫。vector之所以被認為是一個容器,是因為它能夠像容器一樣存放各種類型的對象,但是一個容器中的對象必須是同一種類型。簡單地說,vector是一個能夠存放任意類型的動態數組,能夠增加和壓縮數據。
vector是一個類模板,不是一種數據類型。可用來定義任意多種數據類型。vector類型的每一種都指定了其保存元素的類型。因此vector <int >等都是數據類型。
vector對象初始化
vector 類定義了好幾種構 造函數,用來定義和初始化 vector 對象。
初始化 vector 對象的方式
vector <T > v1 ; |
vector 保存類型為 T 的對象。默認構造函數 v1 為空。 |
vector < T > v2 ( v1 ); |
v2 是 v1 的一個副本。 |
vector < T > v3 ( n , i ); |
v3 包含 n 個值為 i 的元素。 |
vector < T > v4 ( n ); |
v4 含有值初始化的元素的 n 個副本。 |
創建確定個數的元素
若要創建非空的 vector 對象,必須給出初始化元素的值。當把一個 vector 對象復制到另一個 vector 對象時,新復制的 vector 中每一個元素都初始化為原 vector 中相應元素的副本。但這兩個 vector 對象必須保存同一種元素類型:
vector<int> ivec1; // ivec1 holds objects of type int
vector<int> ivec2(ivec1); // ok: copy elements of ivec1 into ivec2
vector<string> svec(ivec1); // error: svec holds strings, not ints
可以用元素個數和元素值對 vector 對象進行初始化。構造函數用元素個數來決定 vector 對象保存元素的個數,元素值指定每個元素的初始值:
vector<int> ivec4(10, -1); // 10 elements, each initialized to -1
vector<string> svec(10, "hi!"); // 10 strings, each initialized to "hi!"
值初始化
如果沒有給出元素的初始化式,那么標准庫將提供一個 值初始化的 ( value initialized )元素初始化式。這個由庫生成的初始值用於初始化容器中的每個元素。而元素初始化式的值取決於存儲在 vector 中元素的數據類型。
如果 vector 保存內置類型(如 int 類型) 的元素,那么標准庫將用 0 值創建元素初始 化值:
vector<string> fvec(10); // 10 elements, each initialized to 0
如果向量保存類類型(如 string )的元素,標准庫將用該類型的默認構造函數 創建 元素初始值:
vector<string> svec(10); // 10 elements, each an empty string
vector對象操作
vector 基本操作
v. empty() |
如果 v 為空,則返回 true, 否則返回 false 。 |
v . size () |
返回 v 中元素的個數。 |
v . push _ back ( t ) |
在 v 的末尾增加一個值為 t 的元素。 |
v [ n ] |
返回 v 中位置為 n 的元素。 |
v1 = v2 |
把 v1 的元素替換為 v2 中元素的副本。 |
v1 == v2 |
如果 v1 與 v2 相等,則返回 true 。 |
!=, <, <=, >, >= |
保持這些操作符慣有的含義。 |
vector 對象的 size
empty 和 size 操作類似於 string 類型的相關操作。成員函數 size 返回相應 vector 類定義的size_type 的值。
使用 size_type 類型時,必須指出該類型是在哪里定義的。 vector 類型總是 包括 vector 的元素類型:
vector<int>::size_type // ok
vector::size_type // error
向 vector 添加元素
push_back() 操作接受一個元素值,並將它作為一個新的元素添加到 vector 對象的后面,也就是“ 插入 ( push)” 到 vector 對象的 “ 后面 ( back ) ” :
- <span style="font-weight:normal;"><span style="font-size:14px;">// read words from the standard input and store them as elements in a vector
- string word;
- vector<string> text; // empty vector
- while (cin >> word) {
- text.push_back(word); // append word to text
- }</span></span>
該循環從標准輸入讀取一系列 string 對象,逐一追加到 vector 對象的后面。首先定義一個空的 vector 對象 text 。每循環一次就添加一個新元素到 vector 對象,並將從 輸入 讀取的 word 值賦予該元素。當循環結束時, text 就包含了所有讀入的元素。
vector 的下標操作(更推薦用迭代器)
vector 中的對象是沒有命名的,可以按 vector 中對象的位置來訪問它們。通常使用下標操作符來獲取元素。 vector的下標操作類似於 string 類型的下標操作 ( 3 .2 .3 節 ) 。
vector 的下標操作符接受一個值,並返回 vector 中該對應位置的元素。 vector 元素的位置從 0 開始。下例使用 for循環把 vector 中的每個元素值都重置為 0 :
- <span style="font-weight:normal;"><span style="font-size:14px;">// reset the elements in the vector to zero
- for (vector<int>::size_type ix = 0; ix != ivec.size(); ++ix)
- ivec[ix] = 0;</span></span>
和 string 類型的下標操作符一樣, vector 下標操作的結果為左值,因此可以像循環體中所做的那樣實現寫入。另外,和 string 對象的下標操作類似,這里用 size_type 類型作為 vector 下標的類型。
在上例中,即使 ivec 為空, for 循環也會正確執行。 ivec 為空則調用 size 返回 0 ,並且 for 中的測試比較 ix 和 0 。第一次循環時,由於 ix 本身就是 0 ,則條件測試失敗, for 循環體一次也不執行。僅能對確知已存在的元素進行下標操作
初學 C ++ 的程序員可能會認為 vector 的下標操作可以添加元素,其實不然:
- vector<int> ivec; // empty vector
- for (vector<int>::size_type ix = 0; ix != 10; ++ix)
- ivec[ix] = ix; <span style="color:#ff0000;"><strong>// disaster: ivec has no elements</strong></span>
上述程序試圖在 ivec 中插入 10 個新元素,元素值依次為 0 到 9 的整數。但是,這里 ivec 是空的 vector 對象,而且下標只能用於獲取已存在的元素。
這個循環的正確寫法應該是:
- for (vector<int>::size_type ix = 0; ix != 10; ++ix)
- ivec.push_back(ix); // ok: adds new element with value ix<span style="color:#000000;font-family:Arial;"> </span>
必須是已存在的元素才能用下標操作符進行索引。通過下標操作進行賦值時,不會添加任何元素。
對於下標操作符 ( [] 操作符 ) 的使用有一點非常重要,就是僅能提取確實已存在的元素,例如:
- vector<int> ivec; // empty vector
- cout << ivec[0]; // Error: ivec has no elements!
- vector<int> ivec2(10); // vector with 10 elements
- cout << ivec[10]; // Error: ivec has elements 0...9
試圖獲取不存在的元素必然產生運行時錯誤。和大多數同類錯誤一樣,不能確保執行過程可以捕捉到這類錯誤,運行程序的結果是不確定的。由於取不存在的元素的結果是未定義的,因而不同的實現會導致不同的結果,但程序運行時幾乎肯定會以某種有趣的方式失敗。
本警告適用於任何使用下標操作的時候,如 string 類型的下標操作,以及將要簡要介紹的內置數組的下標操作。
不幸的是,試圖對不存在的元素進行下標操作是程序設計過程中經常會犯的嚴重錯誤。所謂的“緩沖區溢出”錯誤就是對不存在的元素進行下標操作的結果。這樣的缺陷往往導致 PC 機和其他應用中最常見的安全問題。
其他以及迭代器
① v.resize(2*v.size)或v.resize(2*v.size, 99) 將v的容量翻倍(並把新元素的值初始化為99)
②使用迭代器訪問元素.
vector<int>::iterator it;
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<endl;
- c.insert(pos,elem) // 在pos位置插入一個elem拷貝,傳回新數據位置。
- c.insert(pos,n,elem) // 在pos位置插入n個elem數據。無返回值。
- c.insert(pos,beg,end) // 在pos位置插入在[beg,end)區間的數據。無返回值。
④
c.erase(pos) 刪除pos位置的數據,傳回下一個數據的位置。
c.erase(beg,end) 刪除[beg,end)區間的數據,傳回下一個數據的位置。
⑤
c.assign(beg,end) 將[beg; end)區間中的數據賦值給c
c.assign(n,elem) 將n個elem的拷貝賦值給c。
⑥ c.at(idx) 傳回索引idx所指的數據,如果idx越界,拋出out_of_range。
⑦c.back() 傳回最后一個數據,不檢查這個數據是否存在。
⑧ c.begin()傳回迭代器中的第一個數據
c.clear()移除容器中所有數據。
c.empty()判斷容器是否為空。
c.end()指向迭代器中末端元素的下一個,指向一個不存在元素。
其他更多參見百科:http://baike.baidu.com/link?url=L6vhhZKTvp6C62nPFPbYKnxbqXnRUTwt-2dV7e07ACU0CnFJ6kbyDbwQ-iPGqoY_More:vector結構體
vector的元素不僅僅可以使int,double,string,還可以是結構體,但是要注意:結構體要定義為全局的,否則會出錯。下面是一段簡短的程序代碼:
- #include<stdio.h>
- #include<algorithm>
- #include<vector>
- #include<iostream>
- using namespace std;
- typedef struct rect
- {
- int id;
- int length;
- int width;
- //對於向量元素是結構體的,可在結構體內部定義比較函數,下面按照id,length,width升序排序。
- bool operator< (const rect &a) const
- {
- if(id!=a.id)
- return id<a.id;
- else
- {
- if(length!=a.length)
- return length<a.length;
- else
- return width<a.width;
- }
- }
- }Rect;
- int main()
- {
- vector<Rect> vec;
- Rect rect;
- rect.id=1;
- rect.length=2;
- rect.width=3;
- vec.push_back(rect);
- vector<Rect>::iterator it=vec.begin();
- cout<<(*it).id<<' '<<(*it).length<<' '<<(*it).width<<endl;
- return 0;
- }
算法:
#include<algorithm>中的泛函算法搜索算法:find() 、search() 、count() 、find_if() 、search_if() 、count_if()
分類排序:sort() 、merge()
刪除算法:unique() 、remove()
生成和變異:generate() 、fill() 、transformation() 、copy()
關系算法:equal() 、min() 、max()
sort(v1.begin(),vi.begin()+v1.size/2); 對v1的前半段元素排序
list<char>::iterator pMiddle =find(cList.begin(),cList.end(),'A');找到則返回被查內容第一次出現處指針,否則返回end()。
vector< typeName >::size_type x ; vector< typeName >類型的計數,可用於循環如同for(int i)
使用reverse將元素翻轉
reverse(vec.begin(),vec.end());將元素翻轉(在vector中,如果一個函數中需要兩個迭代器,
一般后一個都不包含.)
使用sort排序
sort(vec.begin(),vec.end());(默認是按升序排列,即從小到大).
可以通過重寫排序比較函數按照降序比較,如下:
定義排序比較函數:
- bool Comp(const int &a,const int &b)
- {
- return a>b;
- }
- /*
- vector 綜合練習
- Written by C_SuooL_Hu
- 2013 10 29
- */
- #include <vector>
- #include <string>
- #include <iostream>
- #include <algorithm>
- using namespace std ;
- int main()
- {
- // 四種初始化方式
- vector<int> ivec_1;
- vector<int> ivec_2(ivec_1);
- vector<int> ivec_3(10, 0) ;
- vector<int> ivec(10);
- // 定義迭代器變量
- vector<int>::iterator iter;
- // 定義下標變量
- vector<int>::size_type ix ;
- system("echo off");
- system("color 3") ;
- // reset all the elements in ivec to 0
- // 使用下標操作,重置為1
- for (ix = 0; ix != ivec.size(); ++ix)
- ivec[ix] = 1;
- // print what we've got so far: should print 10 0's
- cout << "使用下標賦值為1的vector<int>類型(同樣用下標遍歷輸出):"<< endl;
- for (ix = 0; ix != ivec.size(); ++ix)
- cout << ivec[ix] << " ";
- cout << endl;
- // 使用迭代器的操作賦值,重置為0
- for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
- *iter = 0;
- // 遍歷輸出,使用迭代器
- cout<<"使用迭代器賦值為0的vector<int>類型(同樣用迭代器遍歷輸出):" << endl;
- for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
- cout<< *iter << ' ' ;
- cout<< endl ;
- iter = ivec.begin();
- while (iter != ivec.end())
- {
- *iter =2 ;
- ++iter;
- }
- // 遍歷輸出,使用迭代器
- cout<<"使用while循環的迭代器賦值為2的數列的vector<int>類型(同樣用迭代器遍歷輸出):" << endl;
- for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
- cout<< *iter << ' ' ;
- cout<< endl << endl ;
- // 使用vector的成員函數操作vector<int>類型數據
- // 添加元素
- cout << "使用vector的成員函數操作vector<int>類型數據" << endl;
- cout << "添加元素" << endl ;
- cout << "使用迭代器,添加九個遞增元素" << endl ;
- for (ix = 0; ix != 10; ++ ix)
- ivec.push_back(ix);
- cout << "此時ivec共有" << ivec.size() << "個元素"<< endl;
- // 遍歷輸出,使用迭代器
- cout<<"使用下標增加元素為遞增的的數列的vector<int>類型(同樣用迭代器遍歷輸出):" << endl;
- for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
- cout<< *iter << ' ' ;
- cout<< endl << endl;
- // 插入元素
- cout << "插入元素:在第二個位置插入一個43" << endl ;
- ivec.insert(ivec.begin() + 1, 43); // 在2位置插入一個43拷貝,傳回新數據位置。
- // 遍歷輸出,使用迭代器
- cout<<"使用迭代器遍歷輸出:" << endl;
- for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
- cout<< *iter << ' ' ;
- cout << "\n此時ivec共有" << ivec.size() << "個元素" ;
- cout<< endl << endl ;
- cout << "插入元素:在第一個位置插入三個13" << endl ;
- ivec.insert(ivec.begin(), 3 , 13); // 在1位置插入3個13數據。無返回值。
- // 遍歷輸出,使用迭代器
- cout<<"使用迭代器遍歷輸出:" << endl;
- for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
- cout<< *iter << ' ' ;
- cout << "\n此時ivec共有" << ivec.size() << "個元素";
- cout<< endl << endl ;
- cout << "插入元素:在第7個位置插入ivec的[1, 6) 之間的數據:" << endl ;
- ivec.insert(ivec.begin()+6, ivec.begin(), ivec.begin()+5); // 在7位置插入在[10,19)區間的數據。無返回
- // 遍歷輸出,使用迭代器
- cout<<"使用迭代器遍歷輸出:" << endl;
- for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
- cout<< *iter << ' ' ;
- cout << "\n此時ivec共有" << ivec.size() << "個元素";
- cout<< endl << endl ;
- cout << "使用assign賦值ivec_1(將ivec的第[10,19)個元素賦值給他):" <<endl ;
- ivec_1.assign(ivec.begin()+9, ivec.begin()+18);
- cout<<"使用迭代器遍歷輸出:" << endl;
- for (iter = ivec_1.begin(); iter !=ivec_1.end(); ++iter )
- cout<< *iter << ' ' ;
- cout << "\n此時ivec_1共有" << ivec_1.size() << "個元素";
- cout << endl;
- cout << "使用assign賦值ivec_2:" <<endl ;
- ivec_2.assign(10,8) ;
- cout<<"使用迭代器遍歷輸出:" << endl;
- for (iter = ivec_2.begin(); iter !=ivec_2.end(); ++iter )
- cout<< *iter << ' ' ;
- cout << "\n此時ivec_2共有" << ivec_2.size() << "個元素";
- cout << endl;
- // 元素排序
- /*
- 由於vc 6.0對模板庫支持不夠好,這里的排序函數無法通過編譯,但是使用vs2010編譯通過。
- cout << "對ivec排序:" << endl;
- bool Comp(const int &a,const int &b)
- {
- return a>b;
- }
- sort (ivec.begin(), ivec.end,Comp);
- cout<<"從大到小排序后,使用迭代器遍歷輸出:" << endl;
- for (iter = ivec_2.begin(); iter !=ivec_2.end(); ++iter )
- cout<< *iter << ' ' ;
- */
- cout << "是否為空(0代表不是,1代表是):" << ivec.empty() << endl;
- ivec.clear() ;
- cout << "清空元素" << endl;
- cout << "是否為空:" << ivec.empty() << endl;
- return 0;
- }
運行結果:
