C++——標準模板庫
1、泛型程式設計:將程式儘可能寫的通用,將演算法從特定的資料結構中抽象出來,成為通用的;C++模板為泛型程式設計奠定了關鍵的基礎;STL是泛型程式設計的一個範例:容器container、迭代器iterator、演算法algorithms和函式物件function object。
2、名稱空間namespace:一個名稱空間將不同的識別符號集合在一個命名作用域(named scope)中,是為了解決命名衝突。沒有宣告名稱空間的識別符號都處在無名的名稱空間中。
例如,宣告一個名稱空間NS:
namspace NS {
class File;
void Fun ();
}
則引用識別符號的方式如下,
NS:: File obj;
NS:: Fun ();
可以利用using namespace std;指定在名稱空間std中所有識別符號都可以直接飲用,using NS::file;在當前作用域中就可以直接飲用file。
在新的C++標準程式庫中,所有識別符號都宣告在名稱空間std中,標頭檔案都不使用副檔名。
3、容器:容器類是容納、包含一組元素或元素集合的物件。異類容器類與同類容器類。還可以分為順序容器與關聯容器。七種基本容器:向量(vector)、雙端佇列(deque)、列表(list)、集合(set)、多重集合(multiset)、對映(map)和多重對映(multimap)
容器的介面:外界可以使用的功能。包括方法函式和運算子。
通用運算子:==,!=,>,>=,<,<=,=
迭代方法begin(),end(),rbegin(),rend();訪問方法size(),max_size(),swap(),empty()
順序容器:介面:插入方法 push_front(), push_back(), insert(), 運算子"="。
刪除方法 pop(), erase(),clear()
迭代訪問方法 使用迭代器
其他順序容器訪問方法(不修改的訪問方法) front(),back(),下標運算子[]。
順序容器向量:向量屬於順序容器,用於容納不定長的線性序列,提供對序列的快速隨機訪問,就是直接訪問。向量是動態結構,它的大小不固定,可以在程式執行時增加或者減少。
例子:求反問2~N中的質數,N在程式執行時由鍵盤輸入。
#include <iostream>
#include <iomanip>
#include <vector> //包含向量容器標頭檔案
using namespace std ;
int main()
{
vector<int> A(10); // 用來存放質數的向量,初始狀態有10個元素。
int n; //質數範圍的上限,執行時輸入
int primecount = 0, i, j;
cout << "Enter a value >= 2 as upper limit for prime numbers: ";
cin >> n;
A[primecount++] = 2; // 2是一個質數
for(i = 3; i < n; i++)
{
if (primecount == A.size()) // 如果質數表已滿,則再申請10個元素的空間
A.resize(primecount + 10);
if (i % 2 == 0) //大於2的偶數不是質數,因此略過本次迴圈的後繼部分
continue;
// 檢查3,5,7,...,i/2是否i的因子
j = 3;
while (j <= i/2 && i % j != 0)
j += 2;
if (j > i/2) // 若上述引數均不為i的因子,則i為質數
A[primecount++] = i;
}
for (i = 0; i < primecount; i++) //輸出質數
{
cout << setw(5) << A[i];
if ((i+1) % 10 == 0) //每輸出10個數換行一次
cout << endl;
}
cout << endl;
}
4、介面卡:介面卡是一種介面類,為已有的類提供新的介面,目的是簡化、約束,使之安全、隱藏或者改變被修改類提供的服務的集合。主要有三種介面卡型別:容器介面卡(用來擴充套件7中基本容器),迭代器介面卡和函式物件介面卡。
5、迭代器:是面向物件版本的指標,提供了訪問容器、序列中每個元素的方法
輸入迭代器
可以用來從序列中讀取資料
輸出迭代器
允許向序列中寫入資料
前向迭代器
既是輸入迭代器又是輸出迭代器,並且可以對序列進行單向的遍歷
雙向迭代器
與前向迭代器相似,但是在兩個方向上都可以對資料遍歷
隨機訪問迭代器
也是雙向迭代器,但能夠在序列中的任意兩個位置之間進行跳轉。
6、演算法:標準模板庫中包括了70多個演算法,其中包括了查詢演算法、排序演算法、消除演算法、計數演算法、比較演算法、變換演算法、置換演算法和容器管理等等
演算法是一種函式模板,可以分為
不可變序列演算法(non-mutating algorithms),不直接修改所操作的容器內容的演算法
可變序列演算法(mutating algorithms),可以修改它們所操作的容器的元素。
排序相關演算法和數值演算法
例6-1,應用不可變序列演算法對資料序列進行分析
例6-2,以可變序列演算法對資料序列進行復制,生成,刪除,替換,倒序,旋轉等可變性操作。
例6-3,應用排序相關演算法對序列進行各項操作
例6-4,應用數值演算法對資料序列進行操作
//6-1.cpp
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
int main()
{
int iarray[]={0,1,2,3,4,5,6,6,6,7,8};
vector<int> ivector(iarray,iarray+sizeof(iarray)/sizeof(int));
int iarray1[]={6,6};
vector<int> ivector1(iarray1,iarray1+sizeof(iarray1)/sizeof(int));
int iarray2[]={5,6};
vector<int> ivector2(iarray2,iarray2+sizeof(iarray2)/sizeof(int));
int iarray3[]={0,1,2,3,4,5,7,7,7,9,7};
vector<int> ivector3(iarray3,iarray3+sizeof(iarray3)/sizeof(int));
//找出ivector之中相鄰元素值相等的第一個元素
cout<<*adjacent_find(ivector.begin(),ivector.end())<<endl;
//找出ivector之中元素值為6的元素個數
cout<<count(ivector.begin(),ivector.end(),6)<<endl;
//找出ivector之中小於7的元素個數
cout<<count_if(ivector.begin(),ivector.end(),bind2nd(less<int>(),7))<<endl;
//找出ivector之中元素值為4的第一個元素所在位置的元素
cout<<*find(ivector.begin(),ivector.end(),4)<<endl;
//找出ivector之中大於2的第一個元素所在位置的元素
cout<<*find_if(ivector.begin(),ivector.end(),bind2nd(greater<int>(),2))
<<endl;
//找出ivector之中子序列ivector1所出現的最後一個位置,再往後3個位置的元素
cout<<*(find_end(ivector.begin(),ivector.end(),ivector1.begin(),
ivector1.end())+3)<<endl;
//找出ivector之中子序列ivector1所出現的第一個位置,再往後3個位置的元素
cout<<*(find_first_of(ivector.begin(),ivector.end(),ivector1.begin(),
ivector1.end())+3)<<endl;
//子序列ivector2在ivector中出現的起點位置元素
cout<<*search(ivector.begin(),ivector.end(),ivector2.begin(),ivector2.end())
<<endl;
//查詢連續出現3個6的起點位置元素
cout<<*search_n(ivector.begin(),ivector.end(),3,6,equal_to<int>())<<endl;
//判斷兩個區間ivector和ivector3相等否(0為假,1為真)
cout << equal(ivector.begin(), ivector.end(), ivector3.begin()) << endl;
//查詢區間ivector3在ivector中不匹配點的位置
pair<int*,int*>result=mismatch(ivector.begin(),ivector.end(),ivector3.begin());
cout<< result.first - ivector.begin() << endl;
}
//6-2.cpp
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
class even_by_two{ //類定義形式的函式物件
public:
int operator()() const
{return _x+=2;}
private:
static int _x;
};
int even_by_two::_x=0; //靜態資料成員初始化
int main()
{
int iarray[]={0,1,2,3,4,5,6,6,6,7,8};
int iarray1[]={0,1,2,3,4,4,5,5,6,6,6,6,6,7,8};
vector<int> ivector(iarray,iarray+sizeof(iarray)/sizeof(int));
vector<int> ivector1(iarray+6,iarray+8);
vector<int> ivector2(iarray1,iarray1+sizeof(iarray1)/sizeof(int));
ostream_iterator< int > output( cout, " " ); //定義流迭代器用於輸出資料
//迭代遍歷ivector1區間,對每一個元素進行even_by_two操作
generate(ivector1.begin(),ivector1.end(),even_by_two());
copy(ivector1.begin(),ivector1.end(),output);
cout<<endl;
//迭代遍歷ivector的指定區間(起點和長度),對每一個元素進行even_by_two操作
generate_n(ivector.begin(),3,even_by_two());
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//刪除元素6
remove(ivector.begin(),ivector.end(),6);
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//刪除(實際並未從原序列中刪除)元素6,結果置於另一個區間
vector<int> ivector3(12);
remove_copy(ivector.begin(),ivector.end(),ivector3.begin(),6);
copy(ivector3.begin(),ivector3.end(),output);
cout<<endl;
//刪除(實際並未從原序列中刪除)小於6的元素
remove_if(ivector.begin(),ivector.end(),bind2nd(less<int>(),6));
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//刪除(實際並未從原序列中刪除)小於7的元素,結果置於另一個區間,
remove_copy_if(ivector.begin(),ivector.end(),ivector3.begin(),
bind2nd(less<int>(),7));
copy(ivector3.begin(),ivector3.end(),output);
cout<<endl;
//將所有的元素值6,改為元素值3
replace(ivector.begin(),ivector.end(),6,3);
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//將所有的元素值3,改為元素值5,結果放置到另一個區間
replace_copy(ivector.begin(),ivector.end(),ivector3.begin(),3,5);
copy(ivector3.begin(),ivector3.end(),output);
cout<<endl;
//將所有小於5的元素值,改為元素值2
replace_if(ivector.begin(),ivector.end(),bind2nd(less<int>(),5),2);
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//將所有的元素值8,改為元素值9,結果放置到另一個區間
replace_copy_if(ivector.begin(),ivector.end(),ivector3.begin(),
bind2nd(equal_to<int>(),8),9);
copy(ivector3.begin(),ivector3.end(),output);
cout<<endl;
//逆向重排每一個元素
reverse(ivector.begin(),ivector.end());
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//逆向重排每一個元素,結果置於另一個區間
reverse_copy(ivector.begin(),ivector.end(),ivector3.begin());
copy(ivector3.begin(),ivector3.end(),output);
cout<<endl;
//旋轉(互換元素)[first,middle), 和[middle,end)
rotate(ivector.begin(),ivector.begin()+4,ivector.end());
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//旋轉(互換元素)[first,middle], 和[middle,end],結果置於另一個區間,
rotate_copy(ivector.begin(),ivector.begin()+5,ivector.end(),
ivector3.begin());
copy(ivector3.begin(),ivector3.end(),output);
cout<<endl;
}
//6-3.cpp
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
int main()
{
int iarray[]={26,17,15,22,23,33,32,40};
vector<int> ivector(iarray,iarray+sizeof(iarray)/sizeof(int));
// 查詢並輸出最大、最小值元素
cout<<*max_element(ivector.begin(),ivector.end())<<endl;
cout<<*min_element(ivector.begin(),ivector.end())<<endl;
//將ivector.begin()+4-ivector.begin()各元素排序,
//放進[ivector.begin(),ivector.begin()+4]區間。剩餘元素不保證維持原來相對次序
partial_sort(ivector.begin(),ivector.begin()+3,ivector.end());
copy(ivector.begin(),ivector.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//區域性排序並複製到別處
vector<int> ivector1(5);
partial_sort_copy(ivector.begin(),ivector.end(),ivector1.begin(),
ivector1.end());
copy(ivector1.begin(),ivector1.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//排序,預設為遞增。
sort(ivector.begin(),ivector.end());
copy(ivector.begin(),ivector.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//將指定元素插入到區間內不影響區間原來排序的最低、最高位置
cout<<*lower_bound(ivector.begin(),ivector.end(),24)<<endl;
cout<<*upper_bound(ivector.begin(),ivector.end(),24)<<endl;
//對於有序區間,可以用二分查詢方法尋找某個元素
cout<<binary_search(ivector.begin(),ivector.end(),33)<<endl;
cout<<binary_search(ivector.begin(),ivector.end(),34)<<endl;
//下一個排列組合
next_permutation(ivector.begin(),ivector.end());
copy(ivector.begin(),ivector.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//上一個排列組合
prev_permutation(ivector.begin(),ivector.end());
copy(ivector.begin(),ivector.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//合併兩個序列ivector和ivector1,並將結果放到ivector2中
vector<int> ivector2(13);
merge(ivector.begin(),ivector.end(),ivector1.begin(),ivector1.end(),
ivector2.begin());
copy(ivector2.begin(),ivector2.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//將小於*(ivector.begin()+5)的元素放置在該元素之左
//其餘置於該元素之右。不保證維持原有的相對位置
nth_element(ivector2.begin(),ivector2.begin()+5,ivector2.end());
copy(ivector2.begin(),ivector2.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//排序,並保持原來相對位置
stable_sort(ivector2.begin(),ivector2.end());
copy(ivector2.begin(),ivector2.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//針對一個有序區間,找出其中一個子區間,其中每個元素都與某特定元素值相同
pair<vector<int>::iterator,vector<int>::iterator> pairIte;
pairIte=equal_range(ivector2.begin(),ivector2.end(),22);
cout<<*(pairIte.first)<<endl;
cout<<*(pairIte.second)<<endl;
//合併兩個有序序列,然後就地替換
int iarray3[] = { 1, 3, 5, 7, 2, 4, 6, 8 };
vector<int> ivector3(iarray3,iarray3+sizeof(iarray3)/sizeof(int));
inplace_merge(ivector3.begin(), ivector3.begin()+ 4, ivector3.end());
copy(ivector3.begin(),ivector3.end(), ostream_iterator<int>(cout, " "));
cout<<endl;
//以字典順序比較序列ivector3和ivector4
int iarray4[] = { 1, 3, 5, 7,1, 5, 9, 3 };
vector<int> ivector4(iarray4,iarray4+sizeof(iarray4)/sizeof(int));
cout<< lexicographical_compare(ivector3.begin(),ivector3.end(),
ivector4.begin(),ivector4.end()) << endl;
}
//6-4.cpp
#include <iostream>
#include <numeric>
#include <functional>
#include <vector>
using namespace std;
int main()
{
int iarray[]={1,2,3,4,5};
vector<int> ivector(iarray,iarray+sizeof(iarray)/sizeof(int));
//元素的累計
cout<<accumulate(ivector.begin(),ivector.end(),0)<<endl;
//向量的內積
cout<<inner_product(ivector.begin(),ivector.end(),ivector.begin(),10)<<endl;
//向量容器中元素區域性求和
partial_sum(ivector.begin(),ivector.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//向量容器中相鄰元素的差值
adjacent_difference(ivector.begin(),ivector.end(),
ostream_iterator<int>(cout," "));
cout<<endl;
}
7、函式物件:一個行為類似於函式的物件,它可以沒有引數,也可以帶有若干引數,其功能是獲取一個值,或者改變操作的狀態。任何普通的函式和任何過載了呼叫運算子operate()的類的物件都滿足函式物件的特徵,STL中也定義了一些標準的函式物件,如果以功能劃分,可以分為算術運算、關係運算、邏輯運算三大類。為了呼叫這些標準函式物件,需要包含標頭檔案<functional>。