C++STL教程之vector模板的使用
vector模板類
STL(標準模板庫)提供瞭容器、迭代器、函數對象、算法的模板。容器是類似於數組的東西,它可以存儲若幹值,STL容器是同質的,即存儲的值的類型相同;迭代器是用來遍歷容器的,它和能遍歷數組的指針類似,是廣義指針;函數對象是類似於函數的對象,可以是類對象和函數指針;算法就是一些能完成特定任務的處方。
我們來看最簡單的容器:vector
模板類。
1. vector模板類
1.1 創建模板類
在頭文件vector
中定義瞭vector
模板,我們稱之為矢量,它就像是加強版的數組。
創建vector
模板對象:
std::vector<int> first; // empty vector of ints std::vector<int> myadd(5); //vector of five ints std::vector<int> second (4,100); // four ints with value 100 std::vector<int> third (second.begin(),second.end()); // iterating through second std::vector<int> fourth (third); // a copy of third
一般來說,我們使用前三種方式初始化vector
對象,創建好瞭後數組可以做的它都可以,例如我們可以使用[]
隨機訪問數據。
矢量模板類還支持列表初始化語句
std::vector<int> a{1,2,3,4,5};
1.2 STL容器都提供的成員方法
size()
:返回容器中元素數目swap()
:交換兩個容器的內容begin()
:返回一個指向容器第一個元素的迭代器end()
:返回一個表示超過容器尾的迭代器
什麼是迭代器?它是一個廣義指針。它可以是指針,也可以是一個可對其執行–解除引用operator*()
和遞增operator++()
–的對象。每一個容器類都定義瞭一個合適的迭代器,它的類型是一個名為iterator
的typedef
,其作用域是整個類。
我們可以這樣聲明一個迭代器:vector<double>::iterator pd;
也可以使用auto
關鍵字:auto pd=scores.begin();
我們可以使用迭代器pd
進行如下操作:
pd=scores.begin(); *pd=22.3; ++pd; pd++; --pd; pd--;
總之迭代器就相當於是指向容器中元素的指針。
什麼是超過結尾(past-the-end)?它是一種迭代器,指向容器中最後一個元素後面那個元素。例如在C風格字符串中,字符串的末尾的\0
就是超過結尾指向的元素。end()
成員函數會返回超過結尾迭代器。
那麼我們的遍歷可以這樣寫:
for(pd=scores.begin();pd!=scores.end(),pd++) cout<<*pd;
#include<vector> #include<iostream> int main() { using std::cout; using std::endl; using std::vector; vector<double> a{1,2,3,4,5}; vector<double> b{6,7,8}; cout<<"a size: "<<a.size()<<endl; cout<<"b size: "<<b.size()<<endl; cout<<"a :"; for(vector<double>::iterator i=a.begin();i!=a.end();i++) cout<<*i<<" "; cout<<"\nb :"; for(vector<double>::iterator i=b.begin();i!=b.end();i++) cout<<*i<<" "; a.swap(b); cout<<"\nafter swap:"<<endl; cout<<"a :"; for(vector<double>::iterator i=a.begin();i!=a.end();i++) cout<<*i<<" "; cout<<"\nb :"; for(vector<double>::iterator i=b.begin();i!=b.end();i++) cout<<*i<<" "; }
a size: 5
b size: 3
a :1 2 3 4 5
b :6 7 8
after swap:
a :6 7 8
b :1 2 3 4 5
以上代碼是測試瞭,矢量類的一些接口
實際上還有很多接口:例如empty
,front
,back
;可以直接看cplusplus
1.3 vector特有的成員方法
push_back()
:將元素添加到矢量末尾,而且矢量長度會自動增大erase()
:刪除給定區間內的元素insert()
:插入指定區間內的元素
push_back()
接受一個元素類型的參數,它相當於在矢量的超過末尾的地方加個元素:
vector<double> scores; double temp=1.23; scores.push_back(temp);
erase()
接受兩個迭代器參數,這兩個迭代器定義瞭要刪除的區間,第一個迭代器是區間起始處,第二個迭代器是區間終止後的第一個位置,例如a.erase(start,end);
是指刪除區間[start,end)左開右閉中的元素,而C++中所說的區間都是這種左開右閉的區間。
scores.erase(scores.begin(),scores.begin()+2);
上面這句代碼就會刪除矢量對象中前兩個元素。
insert()
會把指定區間裡的元素插到一個位置前面。它接受三個迭代器參數,第一個參數指出新元素的插入位置,第二第三就是區間;
vector<int> old_v; vector<int> new_v; ... old_v.insert(old_v.begin(),new_v.begin()+1,new_v.end());
上面這段代碼會把new_v
中除瞭第一個元素外的所有元素插到old_v
的第一個元素的前面。
超尾元素的存在,使得在最後一個元素後面插入元素變得簡單:
old_v.insert(old_v.end(),new_v.begin()+1,new_v.end());
#include<vector> #include<iostream> int main() { using namespace std; vector<int> a; a.push_back(1); a.push_back(2); cout<<"a: "; for(auto i=a.begin();i!=a.end();i++) cout<<*i; cout<<endl; vector<int>b{3,4,5,6,7}; a.insert(a.end(),b.begin(),b.begin()+3); cout<<"after insert: "; cout<<"a: "; for(auto i=a.begin();i!=a.end();i++) cout<<*i; cout<<endl; a.erase(a.begin()+1,a.begin()+3); cout<<"after erase: "; cout<<"a: "; for(auto i=a.begin();i!=a.end();i++) cout<<*i; cout<<endl; }
a: 12
after insert: a: 12345
after erase: a: 145
1.4 STL容器的非成員方法
我們會對容器做很多操作,例如搜索,排序。但是這些功能不會放在成員方法中,因為不同的容器類的排序或者搜索方法都是類似的,所以我們為瞭節省代碼,就不會為每個容器單獨寫這種成員方法。但是,即使存在執行相同任務的非成員函數,STL容器可能也會定義相同的成員方法,例如vector
的swap()
成員方法比swap()
非成員方法效率高,但是非成員函數讓您可以交換兩個不同類型的容器的內容。
for_each()
:遍歷random_shuffle()
:隨機排列sort()
:排序
這些方法都定義在頭文件algorithm
中,這就是我們所說的算法。for_each()
接受3個參數,前兩個是定義區間的迭代器,最後一個是指向函數的指針(或者說是函數對象)。for_each()
將被指向的函數應用於容器間的各個元素。但是for_each()
不能修改容器的元素值。我們可以使用它來代替for循環。
for_each(books.begin(),books.end(),foo);//foo是函數名,即函數地址
這個語法很熟悉,很像基於范圍的for循環:
double prices[5]={4.99,10.99,6.87,7.99,8.49}; for(double x:prices) cout<<x<<endl;
for_each(books.begin(),books.end(),foo);//foo是函數名,即函數地址 //等價於 for(auto x:books) foo(x);
但是基於范圍的for循環可以改變容器的內容,我們隻需要函數的參數是引用參數foo(int &);
然後我們的代碼:
for(auto &x:books) foo(x);
random_shuffle()
接受兩個指定區間的迭代器,並隨機排列區間中的元素,但是random_shuffle()
要求容器允許隨機訪問(即使用books[i]
可以直接訪問元素)
random_shuffle(books.begin(),books.end());
sort()
也要求容器支持隨機訪問。
第一個版本的sort()
接受兩個指定區間的迭代器,並且使用<
運算符對容器中的元素進行升序排列:
vector<int> coolstuff; ... sort(coolstuff.begin(),coolstuff.end());
這就意味著,如果容器中的元素的類型必須定義operator<()
。
第二個版本的sort()
接受三個參數,它更實用,前兩個參數是指定區間的迭代器,第三個參數是函數指針(或函數對象)。這個函數指針指向一個返回bool
值,接受兩個元素的函數,如果true
就說明排序正確,如果false
就說明排序錯誤。
例如我們希望采用降序排列:
bool compare(double db1,double db2) { if(db1<db2) return false; else return true; } int main(){ vector<double> a{4.99,10.99,6.87,7.99,8.49}; sort(a.begin(),a.end(),compare); }
或者直接使用函數對象:
sort(a.begin(),a.end(),greater<double>());
這裡使用的greater<double>()
就是函數對象,它返回瞭double
類型的大於運算。
#include<vector> #include<iostream> #include<algorithm> void show(const int &a) { std::cout<<a<<" "; } bool greater(const int &x,const int &y) { return x>y; } int main() { using std::vector; using std::random_shuffle; using std::sort; using std::for_each; using std::cout; vector<int> a; for(int i=0;i<20;i++) a.push_back(i); cout<<"initial: "; for_each(a.begin(),a.end(),show); random_shuffle(a.begin(),a.end()); cout<<"\nafter shaking: "; for_each(a.begin(),a.end(),show); sort(a.begin(),a.end()); cout<<"\nAscending: "; for_each(a.begin(),a.end(),show); sort(a.begin(),a.end(),greater); cout<<"\nDescending: "; for_each(a.begin(),a.end(),show); }
initial: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
after shaking: 12 1 9 2 0 11 7 19 4 15 18 5 14 13 10 16 6 3 8 17
Ascending: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Descending: 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
到此這篇關於C++STL教程之vector模板的使用的文章就介紹到這瞭,更多相關C++ vector模板內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- C++中vector操作方式詳解(多種方式)
- 帶你瞭解C++中vector的用法
- C++中最常用的容器用法與排序實例
- C++vector的用法你都知道嘛
- C++入門筆記之std::vector容器詳解