一、STL簡介
1、什么是STL
STL(Standard Template Library)標準模板庫,主要由容器、迭代器、算法、函數對象、內存分配器和適配器六大部分組成。STL已是標準C++的一部分,使用STL開發系統可以提高開發效率。
2、容器(Containers)
容器類是可以包含其它對象的模板類,如向量類(vector)、鏈表類(list)、雙向隊列類(deque)、集合類(set)和映射類(map)等。其中vector、list、deque為序列式容器,set、map為關聯式容器。如:
vector<int> x;? //向量x,每個分量是int
vector<point> v; //向量v,每個分量是point
list<int> L1;??? //鏈表L1,每個節點是int
3、算法(Algorithms)
STL提供了非常多的數據結構算法,它們在std命名空間的范圍內定義,通過#include<algorithm>獲得對它們的使用權。
注意:算法都是全局函數模板,如:for_each( )、find()、count()和sort()等
4、迭代器(Iterator)
迭代器類似于C++的指針,是一個指示器,用來指示容器中的某個元素,迭代器的出現使得容器與算法的分離成為可能,即使用算法必須使用容器和迭代器。
5、函數對象:具有operator()運算符重載函數的對象。
二、vector技術
1、vector概述
vector是STL提供的最簡單,也是最常用的容器類模板之一,類似于傳統數組。
vector特點:提供了對數組元素的快速、隨機訪問,以及在序列尾部快速、隨機的插入和刪除;vector對象在運行時可以動態改變自身的大小以便容納任何數目的元素。
vector頭文件:vector是在標準頭文件<vector>或在非標準向后兼容頭文件vector.h中定義。
2、vector的成員函數
(1)構造函數:
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個元素。
(2)操作
v.empty();??? // 如果 v 為空,則返回 true,否則返回 false。
v.size();???????? // 返回 v 中元素的個數。
v.push_back(t);?? // 在 v 的末尾增加一個值為 t 的元素。
v.pop_back();??? // 刪除v的末尾元素
v.erase(iter);//刪除iter指示器指示的元素
v.erase(iter_F,iter_L);//刪除指示器iter_F和iter_L之間的所有元素
v.resize(10);???? //改變v的大小為10;
v[n];???????????? // 返回 v 中位置為 n 的元素。
v1 = v2;????????? // 把 v1 的元素替換為 v2 中元素的副本。
v1 == v2;???? ??? // 如果 v1 與 v2 相等,則返回 true。
// !=, <, <=, >, 和>=保持這些操作符慣有的含義。
例題1基本操作練習
#include <vector>
#include <iostream>
using namespace std;
void main()
{
??? vector<int> v(5,8);
??? cout<<"v.size()="<<v.size()<<endl;
??? v.push_back(10);
??? v.push_back(12);
??? cout<<"v.size()="<<v.size()<<endl;
??? for ( int i=0;i<v.size();i++)
?????? cout<<v[i]<<endl;
??? v.pop_back();
??? v.pop_back();
??? v.pop_back();
??? v.pop_back();
??? cout<<"v.size()="<<v.size()<<endl;
??? for ( i=0;i<v.size();i++)
?????? cout<<v[i]<<endl;
}
3、高級操作
迭代器和算法同樣適用于其它容器。
(1)迭代器
迭代器類型:
vector<T>::iterator
舉例:
?????? for (vector<int>::iterator iter=v.begin();iter<v.end();iter++)
????????????? cout<<*iter<<endl;
(2)算法
for_each 算法:
for_each(起始iterator,末尾iterator,函數模板);
舉例:
#pragma warning(disable:4786)
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
void PrintIt(string & S)
{
?????? cout<<S<<endl;
}
void main()
{
?????? vector<string> v;
?????? v.push_back("English");
?????? v.push_back("Math");
?????? v.push_back("Chinese");
?????? v.push_back("Program");
?????? for_each (v.begin(),v.end(),PrintIt);
}
sort算法
sort((起始iterator,末尾iterator);
舉例:
?????? sort(v.begin(),v.end());
?
count算法
count(起始iterator,末尾iterator,某個值)統計某個值的出現次數
舉例:
#pragma warning(disable:4786)
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
void PrintIt(string & S)
{
?????? cout<<S<<endl;
}
void main()
{
?????? vector<int> v;
?????? v.push_back(100);
?????? v.push_back(80);
?????? v.push_back(90);
?????? v.push_back(100);
?????? v.push_back(80);
?????? cout<<count(v.begin(),v.end(),100)<<endl;
}
find算法
find(起始iterator,末尾iterator,某個值)查找某個值是否出現
舉例:
?????? vector<int>::iterator iter;
?????? iter=find(v.begin(),v.end(),100);
?????? if (iter==v.end())
????????????? cout<<"No found!"<<endl;
?????? else
????????????? cout<<*iter<<endl;
count_if和find_if算法:這兩個算法的使用需要借助函數對象完成。
4、vector應用
練習1:vector綜合練習
//文件名:CHAPTER6-24.cpp
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
void pause()? //程序暫停
{?? char c;
??? cout << "\n\nPress return to continue: ";
??? cin.get(c);
??? cout << "\n\n";
}
int main()
{
??? vector<int> v(10,0);?? //定義一個vector變量,大小為10,值都為0
??? ostream_iterator<int> out(cout, " "); ?//定義一個輸出迭代器
??? copy(v.begin(), v.end(), out);// 通過算法函數copy輸出v中全部的數據
??? pause(); //程序輸出為:0 0 0 0 0 0 0 0 0 0
??? vector<int>::iterator i = v.begin(); //定義頭迭代器
??? i += 4;? //指向第5個元素
??? *i++ = 7;? // or v[4] = 7; //使第5個元素值為7,同時迭代器指向下一個元素
??? *i = 9;??? // or v[5] = 9; //賦值第6個元素大小為9
??? copy(v.begin(), v.end(), out); // 把通過迭代器賦值后的所有元素打印出來
??? pause();//程序輸出為: 0 0 0 0 7 9 0 0 0 0
??? vector<int>::iterator where = find(v.begin(), v.end(), 9);//在v中查找值為9的元素,并返回相應的迭代器
??? copy(where, v.end(), out);// 把查找到的元素及其該元素后的數據全部顯示出來。
??? pause();//程序輸出為:9 0 0 0 0
??? where = v.insert(where, 8); //在迭代器指示的元素前插入一個元素,其值為8
??? copy(v.begin(), v.end(), out); //檢驗insert函數的效果
??? pause();//程序輸出為:0 0 0 0 7 8 9 0 0 0 0
??? where += 3;? //迭代器指示當前元素后的第三個元素為當前元素
??? where = v.insert(where, 4); //在當前元素前插入一個元素,值為4
??? copy(v.begin(), v.end(), out);
??? pause();//程序輸出為:0 0 0 0 7 8 9 0 4 0 0 0
??? where -= 6;//迭代器前移6個元素
??? where = v.insert(where, 11); //插入元素11到vector中
??? copy(v.begin(), v.end(), out);
??? pause();//程序輸出為:0 0 11 0 0 7 8 9 0 4 0 0 0
??? v.erase(where+2);? // 刪除迭代器后的第2個元素
??? copy(v.begin(), v.end(), out);
??? pause();//程序輸出為:0 0 11 0 7 8 9 0 4 0 0 0
??? sort(v.begin(), v.end()); //對vector進行由大到小排序
??? copy(v.begin(), v.end(), out);
??? pause();//程序輸出為:0 0 0 0 0 0 0 4 7 8 9 11
??? if (binary_search(v.begin(), v.end(), 8)) // vector的查找
???????? cout << "Yes, 8 occurs in vector v.";
??? else
???????? cout << "No, didn't find 8 in vector v.";
??? pause();//程序輸出為:Yes, 8 occurs in vector v.
??? if (binary_search(v.begin(), v.end(), 12)) //? vector的查找
???????? cout << "Yes, 12 occurs in vector v.";
??? else
???????? cout << "No, didn't find 12 in vector v.";
??? pause();//程序輸出為:No, didn't find 12 in vector v.
??? where = lower_bound(v.begin(), v.end(), 8); //查找第一次出現8的位置
??? copy(where, v.end(), out);
??? pause();//程序輸出為:8 9 11
??? where = lower_bound(v.begin(), v.end(), 0); //查找第一次出現0的位置
??? copy(where, v.end(), out);
??? pause();//程序輸出為:0 0 0 0 0 0 0 4 7 8 9 11
??? where = upper_bound(v.begin(), v.end(), 0); //查找第一次不出現0時的位置
??? copy(where, v.end(), out);
??? pause();//程序輸出為:4 7 8 9 11
??? vector<int> w(v);
??? if (v == w) //兩個vector直接比較
?????? cout << "v and w have the same contents";
??? else
?????? cout << "v and w have different contents";
??? pause();//程序輸出為:v and w have the same contents
??? w[5] = 17;
??? if (v == w)
?????? cout << "v and w have the same contents";
??? else
?????? cout << "v and w have different contents";
??? pause();//程序輸出為:v and w have different contents
??? v[5] = 17;
??? if (v == w)
?????? cout << "v and w have the same contents";
??? else
?????? cout << "v and w have different contents";
??? pause();//程序輸出為:v and w have the same contents
??? return 0;
}
練習2???? 讀入一段文本到vector對象,每個單詞存儲為vector中的一個元素。把vector對象中每個單詞轉化為大寫字母。輸出vector對象中轉化后的元素,每8個單詞為一行輸出。
?
三、deque技術
1、deque概述
deque(double-ended queue)是一種動態的數組形式,可以向兩端發展。
deque特點:也是隨機訪問的數據類型;提供了在序列兩端快速的插入和刪除操作的功能;可以在需要時修改其自身大小。
deque頭文件:deque是在標準頭文件<deque>或在非標準向后兼容頭文件deque.h中定義。
2、deque的成員函數
(1)構造函數:
deque<T> name1;????? ? ?
deque<T> name2 (name1);? ? ?
deque<T> name3(size);??????
deque<T> name4(size,value);???? ???
說明:
第一種創建了一個可容納類型為T的空deque對象name1;
第二種用拷貝構造函數從現有的name1創建了新的deque對象name2;
第三種創建了一個初始大小為size的deque對象name3;
第四種創建了一個初始大小為size,每個元素初始化值為value的deque對象name4;
(2)操作
d.empty();??????? // 如果 d 為空,則返回 true,否則返回 false。
d.size();??? ?????// 返回 d 中元素的個數。
d.push_back(t);? // 在 d 的末尾增加一個值為 t 的元素。
d.push_front(t); // 在 d 的頭部增加一個值為 t 的元素。
d.pop_back();???? // 刪除d的末尾元素
d.pop_front();??? // 刪除d的第一個元素
d.insert(iterator , t); //在d的iterator處插入t。
d.insert(iterator, iter_F,iter_L);
//在d的iterator處插入iter_F到iter_L之間的元素。
d.erase(iter);???? //刪除iter指示器指示的元素
d.erase(iter_F,iter_L);//刪除指示器iter_F和iter_L之間的所有元素
d.resize(10);???? //改變d的大小為10;
d[n]??????????????? // 返回 d 中位置為 n 的元素。
d1=d2?????????????? // 把 d1 的元素替換為 d2 中元素的副本。
d1==d2????????????? // 如果 d1 與 d2 相等,則返回 true。
// !=, <, <=, >, 和>=保持這些操作符慣有的含義。
d.swap(d1);??????? //d和d1容器中的內容互換。
3、高級操作
(1)迭代器
deque<T>iterator
舉例:
?????? for (deque<int>::iterator iter=d.begin();iter<d.end();iter++)
????????????? cout<<*iter<<endl;
(2)算法
for_each()算法、sort()算法、count()算法、find()算法同樣適用于deque容器;
3、deque應用
練習:deque綜合練習
#include <iostream>
#include <deque>??
#include <string>
#include <algorithm>
using namespace std;
int main()
{
?????? //create empty deque of strings
?????? deque<string> coll;
?????? //insert several elements
?????? coll.assign (3, string("string"));
?????? coll.push_back ("last string");
?????? coll.push_front ("first string");
?????? //print elements separated by newlines
?????? copy (coll.begin(), coll.end(),?????? ostream_iterator<string>(cout,"\n"));
?????? cout << endl;
?????? //remove first and last element?????
?????? coll.pop_front();
?????? coll.pop_back();????
?????? //insert ''another'' into every element but the first
?????? for (int i=1; i<coll.size(); ++i) {
????????????? coll[i] = "another " + coll [i];
?????? }
?????? //change size to four elements
?????? coll.resize (5, "resized string");
?????? //print elements separated by newlines
?????? copy (coll.begin(), coll.end(),ostream_iterator<string>(cout,"\n"));
}
四、list技術
1、list概述
list是一個雙向鏈表容器,不支持隨機訪問。
list特點:不支持隨機訪問,訪問鏈表元素要從鏈表的某個端點開始,插入和刪除操作所花費的時間是固定的,即與元素在鏈表中的位置無關;優勢是在任何位置執行插入或刪除動作都非常迅速;可以在需要時修改其自身大小。
list頭文件:list是在標準頭文件<list>或在非標準向后兼容頭文件list.h中定義。
2、list的成員函數
(1)構造函數:
list<T> name1;?????? ? ?
list <T> name2 (name1);? ? ?
list <T> name3(size);??????
list <T> name4(size,value);???? ???
說明:
第一種創建了一個可容納類型為T的空list對象name1;
第二種用拷貝構造函數從現有的name1創建了新的list對象name2;
第三種創建了一個初始大小為size的list對象name3;
第四種創建了一個初始大小為size,每個元素初始化值為value的list對象name4;
(2)操作
d.empty();??????? // 如果 d 為空,則返回 true,否則返回 false。
d.size();???????? // 返回 d 中元素的個數。
d.push_back(t);? // 在 d 的末尾增加一個值為 t 的元素。
d.push_front(t); // 在 d 的頭部增加一個值為 t 的元素。
d.pop_back();???? // 刪除d的末尾元素
d.pop_front();??? // 刪除d的第一個元素
d.front();???????? //返回d的第一個元素的引用
d.back();?????????? //返回d的最后一個元素的引用
d.insert(iterator , t); //在d的iterator處插入t。
d.insert(iterator, iter_F,iter_L);
//在d的iterator處插入iter_F到iter_L之間的元素。
d.erase(iter);//刪除iter指示器指示的元素
d.erase(iter_F,iter_L);//刪除指示器iter_F和iter_L之間的所有元素
d.swap(d1);??????? //d和d1容器中的內容互換。
d.sort();?????????? //list類的排序使用成員函數完成。而不是用通用算法函數。
d.resize(10);???? //改變d的大小為10;
d.merge(d1);?????? //合并d1和d,以升序排列存儲到d中
d.splice(iterator, T);//把另一個list對象T插入到iterator位置
d.splice(iterator,T,iter);//把另一個list對象T的iter位置的元素插入到d的iterator位置。
迭代器
begin()和end()返回頭尾的迭代器;
rbegin()和rend()返回尾頭的反向迭代器:rbegin()返回最后一個元素的迭代器,rbegin++返回倒數第二個元素。(注意:迭代器只能使用==和!=比較,不能使用>或<比較)。
3、list應用
#include <iostream>
#include <list>
#include <algorithm>
#if _MSC_VER > 1020?? // if VC++ version is > 4.2
?? using namespace std;? // std c++ libs implemented in std
#endif
void printLists(const list<int>& l1, const list<int>& l2)
{
?????? cout << "list1: ";
?????? copy (l1.begin(), l1.end(), ostream_iterator<int>(cout," "));
?????? cout << endl << "list2: ";
?????? copy (l2.begin(), l2.end(), ostream_iterator<int>(cout," "));
?????? cout << endl << endl;
};
int main()
{
?????? //create two empty lists
?????? list<int> list1, list2;
?????? //fill both lists with elements
?????? for (int i=0; i<6; ++i)
?????? {
????????????? list1.push_back(i);
????????????? list2.push_front(i);
?????? }
?????? printLists(list1, list2);
?????? ?//insert all elements of list1 before the first element with value 3 of list2
?//-find() returns an iterator to the first element with value 3
?????? list2.splice(find(list2.begin(),list2.end(), // destination position
????????????? 3), list1); // source list
?????? printLists(list1, list2);//move first element to the end
?????? list2.splice(list2.end(), // destination position
????????????? list2, // source list
????????????? list2.begin()); // source position
?????? printLists(list1, list2);
?????? //sort second list, assign to list1 and remove duplicates
?????? list2.sort();
?????? list1 = list2;
?????? list2.unique();
?????? printLists(list1, list2);
?????? //merge both sorted lists into the first list
?????? list1.merge(list2);
?????? printLists(list1, list2);
?????? return 0;
}
五、set技術
1、set概述
set是一種關聯式容器,關聯式容器依據特定的排序準則,自動為其元素排序。set中每個元素只能出現一次。即數學中的集合。
set頭文件:set是在標準頭文件<set>或在非標準向后兼容頭文件set.h中定義。
2、set的成員函數
(1)構造函數:
set<T> s1;??? ? ?
set<T> s2(s1);??? ? ?
(2)操作
s.empty();??????? // 如果 s 為空,則返回 true,否則返回 false。
s.size();???????? // 返回 s 中元素的個數。
s.insert( t);??? //在s中插入t。
s.insert(iter_F,iter_L); //在s中插入iter_F到iter_L之間的元素。
s.erase(iter);?? //刪除iter指示器指示的元素
s.erase(iter_F,iter_L);//刪除指示器iter_F和iter_L之間的所有元素
s.erase(key);??? //刪除s中的key元素。
s.lower_bound(key);//返回key前面的元素的迭代器
s.upper_bound(key);//返回key后面的元素的迭代器
s.find(key); ?????//在s中查找鍵值key,找到返回iterator,否則返回end()。
s.resize(10);???? //改變s的大小為10;
3、set應用
??? 編寫程序通過刪除單詞尾部的’s’生成該單詞的非復數版本。同時建立一個單詞排除集,用于識別以’s’結尾、但這個結尾的’s’又不能刪除的單詞。例如,放在該排除集中的單詞可能有success和class。使用這個排除集編寫程序,刪除輸入單詞的復數后綴,而如果輸入的是排除集的單詞,則保持該單詞不變。
#pragma warning(disable: 4786)
#include <set>
#include <iostream>
int main()
{
?????? std::set<int> c1 ;
?????? int ai[] = {0, 1, 2, 3} ;
?????? //construct from a range
?????? std::set<int> c2(ai, ai + 4) ;
?????? //copy constructor
?????? std::set<int> c3(c2) ;
?????? std::set<int>::iterator Iter ;
?????? std::set<int>::reverse_iterator RevIter ;
?????? //判斷c1是否為空
?????? if(c1.empty())
?????? {??????????? std::cout << "set c1 is empty" << std::endl ; }
?????? else
?????? {??????????? std::cout << "set c1 is not empty" << std::endl ;?? }
?????? //使用begin, end顯示c2所有元素
?????? std::cout << "c2 (using begin, end)? = " ;
?????? for(Iter = c2.begin(); Iter != c2.end(); Iter++)
?????? {??????????? std::cout << *Iter << " " ;???? }
?????? std::cout << std::endl ;
?????? //使用rbegin,rend顯示c2所有元素
?????? std::cout << "c2 (using rbegin, rend) = " ;
?????? for(RevIter = c2.rbegin(); RevIter != c2.rend(); RevIter++)
?????? {??????????? std::cout << *RevIter << " " ;?????? }
?????? std::cout << std::endl ;
?????? //使用find進行元素的查找
?????? std::set<int>::const_iterator constIter = c1.find(3) ;
?????? if(constIter != c1.end())
?????? {??????????? std::cout << "c1 contains element 3, *constIter = "
???????????????????? << *constIter << std::endl ;
?????? }
?????? //使用size返回c1的最大元素大小
?????? std::cout << "c1.size() = " << c1.size() << std::endl ;
?????? //使用swap把c1和c2進行元素交換
?????? c1.insert(4) ;
?????? c2.swap(c1) ;
?????? std::cout << "The last element of c2 = " << *(c2.rbegin())
????????????? << std::endl ;
?????? //使用clear進行c1元素的清除
?????? c1.clear() ;
?????? std::cout << "After calling c1.clear(), c1.size() = "
????????????? << c1.size() << std::endl ;
?????? //使用upper_bound返回c2當前值的最近增值迭代器
?????? std::cout << "* (c2.upper_bound(3)) = "
????????????? << *(c2.upper_bound(3)) << std::endl ;
?????? //使用lower_bound返回c2當前值的最近降值迭代器
?????? std::cout << "* (c2.lower_bound(3)) = "
????????????? << *(c2.lower_bound(3)) << std::endl ;
?????? //使用erase進行元素的刪除操作
?????? if(c3.erase(1) != 0)
?????? {??????????? std::cout << "c3 does not contain 1 any more" << std::endl ;????? }
?????? else
?????? {??????????? std::cout << "No elements in c3 match key 1" << std::endl ;????? }
?????? if((c2.erase(c2.begin())) != c2.end())
?????? {??????????? std::cout << "c2 does not contain 0 any more" << std::endl ;????? }
?????? else
?????? {??????????? std::cout << "No elements in c2 match key 0" << std::endl ;????? }
?????? c3.erase(c3.begin(), c3.end()) ;
?????? std::cout << "after c3.erase(c3.begin(), c3.end()), c3.size() = "
????????????? << c3.size() << std::endl ;
?????? return 0 ;
}
六、map技術
1、map概述
map是一種關聯式容器,set中每個元素都是由“鍵值/實值”所形成的一對組合,每個鍵值只能出現一次,不能重復。
map頭文件:map是在標準頭文件<map>或在非標準向后兼容頭文件map.h中定義。
2、map的成員函數
(1)構造函數:
map<k, v> m2;
// 創建一個名為m2的空map對象,其鍵和值的類型分別為k和v
map<k, v> m(m2);
// 創建m2的副本m,m與m2必須有相同的鍵類型和值類型
map<k, v> m(iter_F, iter_L);
// 創建map類型的對象m,存儲迭代器iter_F和 iter_L標記的范圍內所有元素的副本。元素的類型必須能轉換為pair<const k, v>
對于鍵類型,唯一的約束就是必須支持 < 操作符,至于是否支持其他的關系或相等運算,則不作要求。
(2)操作:
m.empty()、m.size()、m.begin()、m.end()、m.rbegin()、m.rend()、m.swap(m1)、m.lower_bound(key)、m.upper_bound(key)、、
m.insert(pair<k,v>(key,value))、
m.insert(iterator, pair<k,v>(key,value))、
m.erase(iterator)、m.erase(key)、m.erase(iter_F,iter_L)、
m[key]????? //如果下標所表示的鍵在容器中不存在,則添加新元素
3、map應用
(1)編寫程序統計并輸出所讀入的單詞出現次數。
(2)輸入兩個多項式,計算兩個多項式的加法運算結果。