STL(Standard Template Library)標準模板庫是C++最重要的組成部分,它提供了一組表示容器、迭代器、函數對象和演算法的模板。其中容器是存儲類型相同的數據的結構(如vector,list, deque, set, map等),演算法完成特定任務,迭代器用來遍歷容器對象,扮演容器和 ...
STL(Standard Template Library)標準模板庫是C++最重要的組成部分,它提供了一組表示容器、迭代器、函數對象和演算法的模板。其中容器是存儲類型相同的數據的結構(如vector,list, deque, set, map等),演算法完成特定任務,迭代器用來遍歷容器對象,扮演容器和演算法之間的膠合劑。
模板類vector 在計算中,矢量(vector)對應數組,它的數據安排以及操作方式,與array非常類似。在C++中,使用vector模板類時,需要頭文件包含#include<vector>,並聲明使用using std::vector或者using namespace std; (1)vector初始化 要創建vector模板對象,可使用<type>表示法來指出所使用的類型,vector通過類函數重載,支持多種初始化方式。int a[5] = {5, 1, 2, 0, 3}; vector<int> v0(a, a+4); vector<int> v1(v0); vector<int> v2(v0.begin(), v0.begin()+2); vector<int> v3(5);如果編譯器支持C++11, 可以採用列表初始化,結果相同。
vector<int> v{5, 1, 2, 0, 3};
(2)vector方法
C++ STL除了分配空間外,還提供了一些基本方法,下麵將詳細講解這些方法。 push_back 向容器的末尾添加元素,容器內元素個數加1 pop_back 刪除容器尾端元素,容器內元素個數減1.v1.push_back(rand()%100); v1.pop_back();size 容器內當前元素個數 capacity 容器當前容量 empty 判斷容器是否為空
cout<<v1.size()<<endl; cout<<v1.capacity()<<endl; if(!v1.empty()) { v1.pop_back(); cout<<"v1 is not empty!"<<endl; }resize 修改當前容器內元素個數,大於當前數則插入相應數據,小於則刪除末尾相應區間。 reserve 修改當前容器容量,大於當前容量則申請相應空間,小於則不處理。
v1.resize(9, 6);
v1.reserve(14);
insert 在容器指定區間插入一個或者多個元素
earse 刪除容器內一個或者指定區間內所有元素
v0.insert(v0.begin(), a[0]); v1.insert(v1.begin(), a, a+2); v1.insert(v1.begin(), v0.begin()+2, v0.begin()+4); v1.earse(v1.end()-6); v1.earse(v1.end()-6, v1.end());front 返回容器的第一個元素 back 返回容器的最後一個元素
cout<<v1.front()<<endl;
cout<<v1.end()<<endl;
clear 清空容器內元素,僅修改size,不影響容器容量
swap 交換兩容器內內容,用於容量收縮
v1.clear(); vector<int>().swap(v1);begin 返回指向vector首位的迭代器 end 返回指向vector末位的迭代器 基於迭代器,就可以簡單的實現vector的遍歷。
for(vector<int>::iterator iter0=vt1.begin(); iter0!=vt1.end(); iter0++) {cout<<*iter0;}
當然,C++11提供了類型推導,上述語句可簡化為為
for(auto iter0=vt1.begin(); iter0!=vt1.end(); iter0++) {cout<<*iter0;}不過vector重載了[]運算符,也可以用
for(unsinged int i=0; i<vt1.size(); i++) {cout<<vt1[i];}在下小節中,將根據STL提供演算法,用於更方便的遍歷和處理vector。 (3)用於vector的演算法(常見演算法) STL提供大量的演算法用於容器的操作,這裡主要以常用的for_each(遍歷), sort(排序), random_shuffle(隨機排列)三種演算法來簡單演示STL演算法的應用,使用演算法要包含頭文件#include <algorithm>。 for_each 遍歷容器,將被指向的函數應用於容器區間的每個元素。
void ShowInt(int &s) { cout<<s<<" "; } for_each(v1.begin(), v1.end(), ShowInt); //C++11支持lambada表達式,可以寫成一句話: for_each(v1.begin(), v1.end(), [](int &s){ cout<<s<<" "; });
sort 容器內對象元素按照指定的規則進行排序,預設按照從小到大排列(不包含比較函數),當然也可以自定義比較函數
bool CompareInt(int &t1, int &t2) { if(t1<t2) return true; return false; } sort(v1.begin(), v1.end(), CompareInt); sort(v1.begin(), v1.end()); //C++11 lambada sort(v1.begin(), v1.end(), [](int &t1, int &t2}->bool{ if(t1<t2) return true; return false; });lower_bound 返回不小於元素值的第一個迭代器(相等或者大於),值可被插入的第一個位置 upper_bound 返回不破壞排序的情況下,值可被插入的最後一個位置
auto iter0 = lower_bound(v1.begin(), v1.end(), 34); cout<<*iter0<<endl; iter0 = upper_bound(v1.begin(), v1.end(), 34); cout<<*iter0<<endl;
random_shuffle 隨機排列容器內元素,其中第三個變數為提供的自定義隨機函數。
random_shuffle(v1.begin(), v1.end()); //C++11 lambada random_shuffle(v1.begin, v1.end(), [](const unsigned int n)->unsigned int{ return rand()%n; });(4) vector用於自定義數據類型 vector容器方便了對於數據的排序,插入,刪除及遍歷操作處理。結合運算符重載,類模板相關定義,將用戶自定義數據類型通過vector進行管理,屬於比較難以理解,但也是運用較多的部分。 因為C++11取消了關鍵字export,也不建議使用,因此類模板的聲明和實現,包括友元函數的實現都要聲明在同一個文件內。
/*****************************************
#device.h
#用戶自定義類模板
#命名空間 user
#用戶自定義類模板 device<T>
#構造函數重載
#一元、 二元運算符重載
*******************************************/
#include <string>
#include <iostream>
using namespace std;
namespace user
{
//自定義類模板
template<class T>
class device
{
public:
//構造函數重載
device(){}
device(T a){id = a; name=" ";}
device(string str){name = str; id=0;}
device(string str, T a){name = str; id = a;}
~device(){};
void show_info();
//一元運算符重載
device<T>& operator++(int);
//二元運算符重載
friend device<T>& operator+ <T>(device<T>&d, string &s);
friend bool operator< <T>(device<T> &d1, device<T> &d2);
friend ostream& operator<< <T>(ostream &out, const device<T> &d);
private:
T id;
string name;
};
template<class T>
void device<T>::show_info(void)
{
cout<<"id:"<<id<<" ";
cout<<"name:"<<name<<endl;
}
template<class T>
ostream& operator<<(ostream &out, const device<T> &d)
{
out<<"id:"<<d.id<<" name:"<<d.name<<"\n";
return out;
}
template<class T>
bool operator<(device<T> &d1, device<T> &d2)
{
if(d1.id < d2.id)
return true;
else if(d1.id == d2.id && d1.name<d2.name)
return true;
else
return false;
}
template<class T>
device<T>& device<T>::operator++(int)
{
this->id++;
return *this;
}
template<class T>
device<T>& operator+(device<T> &d, string &s)
{
d.name = s + d.name;
return d;
}
}
vectorDemo.cpp主要涉及智能指針,用戶自定義類型及STL vector容器及演算法的相應應用。
/***************************************** #VectorDemo.cpp #vector容器方法 #迭代器 #STL演算法 #lambada表達式 #智能指針 *******************************************/ #include "VectorDemo.h" #include <vector> #include <iostream> #include <algorithm> #include <memory> #include "device.h" #include <string> using namespace std; using namespace user; //函數模板 template<class T> void ShowDevice(shared_ptr<device<T>> &s) { cout<<*s; } template<class T> void show_genericity_demo(vector<shared_ptr<device<T>>> &d) { //<<** 三次重載,第一次取智能指針,第二次取對象, 第三次輸出 for(auto iter=d.begin(); iter!=d.end(); iter++) { cout<<**iter; //(*iter)->show_info(); } cout<<endl; } template<class T> bool genericity_compare(shared_ptr<device<T>> &d1, shared_ptr<device<T>> &d2) { //重載運算符< 比較 if((*d1) < (*d2)) return true; else return false; } //複雜容器vector模板,涉及智能指針和用戶自定義類型 int genericity_vector_Demo(void) { shared_ptr<device<int>> spd[5] = { shared_ptr<device<int>>(new device<int>("TV", rand()%100)), shared_ptr<device<int>>(new device<int>("Phone", rand()%100)), shared_ptr<device<int>>(new device<int>("Computer", rand()%100)), shared_ptr<device<int>>(new device<int>("light", rand()%100)), shared_ptr<device<int>>(new device<int>("pot", rand()%100)), }; //vector容器創建和初始化,對象為device對應的智能指針 vector<shared_ptr<device<int>>> vspd(spd, spd+5); //遍歷顯示vector中的所有對象,傳入為shared_ptr指針,因此*號,在通過<< 運算符重載 for_each(vspd.begin(), vspd.end(), ShowDevice<int>); cout<<endl; //排序 lambada表達式 sort(vspd.begin(), vspd.end(), [](shared_ptr<device<int>> &t1, shared_ptr<device<int>> &t2)->bool{ if((*t1)<(*t2)) return true; return false; }); //亂序排列容器內對象 random_shuffle(vspd.begin(), vspd.end()); show_genericity_demo<int>(vspd); cout<<*vspd.front()<<endl; cout<<*vspd.back()<<endl; vspd.push_back(shared_ptr<device<int>>(new device<int>("icebox", rand()%100))); vspd.push_back(shared_ptr<device<int>>(new device<int>("PlayStation", rand()%100))); //排序,因為容器元素為智能指針,不支持省略比較函數方法 sort(vspd.begin(), vspd.end(), genericity_compare<int>); show_genericity_demo<int>(vspd); vspd.pop_back(); show_genericity_demo<int>(vspd); //遍歷 +, ++運算符重載,實現對容器內對象元素修改. for_each(vspd.begin(), vspd.end(), [](shared_ptr<device<int>> &s){ (*s) = (*s) + string("famlily "); (*s)++; }); show_genericity_demo<int>(vspd); return 0; }
相關代碼:容器範例下載
參考書籍:
2. STL源碼剖析