(二)容器的具體介紹
A、順序式容器
1、vector
該標準容器是一個定義在 namespace std 中的模板,該模板的原型聲明在頭文件 <vector> 中。它的數據結構很像一個數組,所以與其他容器相比,vector 能非常方便和高效訪問單個元素。因此,在 vector 中提供隨機訪問循環子。
說明:實際上就是個動態數組。隨機存取任何元素都能在常數時間完成。在尾端增刪元素具有較佳的性能。例1:
int main()
{ int i;
int a[5] = {1,2,3,4,5 };
vector<int> v(5);
cout << v.end()-v.begin() << endl;
for( i = 0;i < v.size();i ++ ) v[i] = i;
v.at(4) = 100;
for( i = 0;i < v.size();i ++ )
cout << v[i] << "," ;
cout << endl;
vector<int> v2(a,a+5); //構造函數
v2.insert( v2.begin() + 2, 13 ); //在begin()+2位置插入 13
for( i = 0;i < v2.size();i ++ )
cout << v2[i] << "," ;
return 0;
}
輸出:
5
0,1,2,3,100,
1,2,13,3,4,5,
例2:
int main() {
const int SIZE = 5;
int a[SIZE] = {1,2,3,4,5 };
vector<int> v (a,a+5); //構造函數
try {
v.at(100) = 7;
}
catch( out_of_range e) {
cout << e.what() << endl;
}
cout << v.front() << “,” << v.back() << endl;
v.erase(v.begin());
ostream_iterator<int> output(cout ,“*");
copy (v.begin(),v.end(),output);
v.erase( v.begin(),v.end()); //等效於 v.clear();
if( v.empty ())
cout << "empty" << endl;
v.insert (v.begin(),a,a+SIZE);
copy (v.begin(),v.end(),output);
}
// 輸出:
invalid vector<T> subscript
1,5
2*3*4*5*empty
1*2*3*4*5*
ostream_iterator<int> output(cout ,“*");//定義了一個 ostream_iterator 對象,可以通過cout輸出以 * 分隔的一個個整數
copy (v.begin(),v.end(),output);//導致v的內容在 cout上輸出
copy 函數模板(算法):
template<class InIt, class OutIt>
OutIt copy(InIt first, InIt last, OutIt x); //本函數對每個在區間[0, last - first)中的N執行一次 *(x+N) = * ( first + N) ,返回 x + N
對於copy (v.begin(),v.end(),output);
first 和 last 的類型是 vector<int>::const_iterator,output 的類型是 ostream_iterator<int>
例3
#include "iostream"
#include "vector"
#include "algorithm"
using namespace std;
int main()
{
istream_iterator<int>inputInt(cin);
int n1,n2;
n1=*inputInt;
inputInt++;
n2=*inputInt;
cout<<n1<<" "<<n2<<endl;
ostream_iterator<int>outputInt(cout);
*outputInt=n1+n2;
cout<<endl;
int a[5]={1,2,3,4,5};
copy(a,a+5,outputInt);
return 1;
}
輸出結果爲:
78,90
168
12345
2、list
該標準容器是一個定義在 namespace std 中的模板,該模板的原型聲明在頭文件 <list> 中。list 是一個對容器元素的插入和刪除操作進行了優化的序列。但與 vector 和 deque 相比,對元素的下標訪問操作的低效是不能容忍的,因此 list 不提供這類操作,即不提供隨機訪問循環子,而提供雙向循環子。這意味着 list 是典型的通過使用雙鏈表實現的序列結構。
說明:雙向鏈表,在任何位置增刪元素都能在常數時間完成。不支持隨機存取。
對於 list,front 操作和 back 操作都同樣高效和方便。因此,如果希望使用 list 編寫的代碼演變爲能應用於多種其他容器的通用代碼,則使用更具廣泛適用性的 back 操作是最好的選擇。list 元素的插入和刪除操作尤爲高效,所以 list 更適合在插入和刪除操作頻繁的應用中使用。
#include "list"
#include "iostream"
using namespace std;
typedef list<int> LISTINT;
int main()
{
int rgTest1[] = {5,6,7};
int rgTest2[] = {10,11,12};
LISTINT listInt;
LISTINT::iterator i;
// Insert one at a time
listInt.insert (listInt.begin(), 2);
listInt.insert (listInt.begin(), 1);
listInt.insert (listInt.end(), 3);
// output: 1 2 3
cout << "listInt:";
for(i=listInt.begin();i!=listInt.end();i++)
cout << " " << *i;
cout <<endl;
// Insert 3 fours
listInt.insert(listInt.end(),3,4);
// output: 1 2 3 4 4 4
cout <<"listInt:";
for (i=listInt.begin();i!=listInt.end();++i)
cout <<" "<< *i;
cout<<endl;
// Insert an array at the end
listInt.insert(listInt.end(),rgTest1,rgTest1+3);
// output: 1 2 3 4 4 4 5 6 7
cout << "listInt:";
for (i=listInt.begin(); i!=listInt.end();++i)
cout << " " << *i;
cout <<endl;
// Insert another LISTINT
LISTINT listAnother;
listAnother.insert (listAnother.begin(),rgTest2,rgTest2+3);
listInt.insert (listInt.end(), listAnother.begin(), listAnother.end());
// output: 1 2 3 4 4 4 5 6 7 10 11 12
cout << "listInt:";
for (i=listInt.begin();i!=listInt.end();++i)
cout <<" "<<*i;
cout <<endl;
return 1;
}
3、deque
該標準容器是一個定義在 namespace std 中的模板,該模板的原型聲明在頭文件 <deque> 中。deque 是一個雙向隊列,也是一個優化序列。在 deque 兩端的操作與 list 一樣高效,對元素的下標操作的效率又與 vector 類似,而對容器元素的插入和刪除操作的效率則介於 list 和 vector 之間。
說明:也是個動態數組,隨機存取任何元素都能在常數時間完成(但性能次於vector)。在兩端增刪元素具有較佳的性能。
所有適用於vector的操作都適用於deque。deque還有push_front(將元素插入到前面)和pop_front(刪除最前面的元素)操作
上述三種容器稱爲順序容器,是因爲元素的插入位置同元素的值無關。
B、關聯式容器
關聯式容器內的元素是排序的,插入任何元素,都按相應的排序準則來確定其位置。關聯式容器的特點是在查找時具有非常好的性能。
set 即集合,set中不允許相同元素,multiset中允許存在相同的元素。
map與set的不同在於map中存放的是成對的key/value,並根據key對元素進行排序,可快速地根據key來檢索元素;map同multimap的不同在於是否允許多個元素有相同的key值。
上述4種容器通常以平衡二叉樹方式實現,插入和檢索的時間都是 O(logN)。
內部元素有序排列,新元素插入的位置取決於它的值,查找速度快。
map關聯數組:元素通過鍵來存儲和讀取;
set大小可變的集合,支持通過鍵實現的快速讀取。
multimap支持同一個鍵多次出現的map類型;
multiset支持同一個鍵多次出現的set類型。
與順序容器的本質區別
關聯容器是通過鍵(key)存儲和讀取元素的,它要求定義一個比較操作進行元素操作。而順序容器則通過元素在容器中的位置順序存儲和訪問元素。
4、map該標準關聯容器是一個定義在 namespace std 中的模板,該模板的原型聲明在頭文件 <map> 中。 map 是一個元素對(關鍵字,映射值)序列(注:Hash table (key, value pairs)),它提供了以關鍵字爲基礎的快速檢索。map 中的每一個關鍵字必須是唯一的。map 提供雙向循環子。
元素按照關鍵字升序排列,缺省情況下用 less 定義“小於”。
可以用pairs[key] 訪形式問map中的元素。pairs 爲map容器名,key爲關鍵字的值。該表達式返回的是對關鍵值爲key的元素的值的引用。(我們可以理解爲map中存儲的數據類型是pairs型)
如果沒有關鍵字爲key的元素,則會往pairs裏插入一個關鍵字爲key的元素,並返回其值的引用如:
map<int,double> pairs;
則 pairs[50] = 5; 會修改pairs中關鍵字爲50的元素,使其值變成5。
例一:
#include <iostream>
#include <map>
using namespace std;
ostream & operator <<( ostream & o,const pair< int,double> & p)
{
o << "(" << p.first << "," << p.second << ")";
return o;
}
int main() {
typedef map<int,double,less<int> > mmid;
mmid pairs;
cout << "1) " << pairs.count(15) << endl;
pairs.insert(mmid::value_type(15,2.7));
pairs.insert(make_pair(15,99.3));//make_pair生成pair對象
cout << "2) " << pairs.count(15) << endl;
pairs.insert(mmid::value_type(20,9.3));
mmid::iterator i;
cout << "3) ";
for( i = pairs.begin(); i != pairs.end();i ++ )
cout << * i << ",";
cout << endl;
cout << "4) ";
int n = pairs[40];//如果沒有關鍵字爲40的元素,則插入一個
for( i = pairs.begin(); i != pairs.end();i ++ )
cout << * i << ",";
cout << endl;
cout << "5) ";
pairs[15] = 6.28; //把關鍵字爲15的元素值改成6.28
for( i = pairs.begin(); i != pairs.end();i ++ )
cout << * i << ",";
return 0;
}
例二:
#include <iostream>
#include "numeric"
#include "string"
#include "map"
using namespace std;
typedef map<int,string,less<int> > INT2STRING;
int main()
{
INT2STRING theMap;
INT2STRING::iterator theIterator;
string theString="";
int index;
theMap.insert(INT2STRING::value_type(0,"Zero"));
theMap.insert(INT2STRING::value_type(1,"One"));
theMap.insert(INT2STRING::value_type(2,"Two"));
theMap.insert(INT2STRING::value_type(3,"There"));
theMap.insert(INT2STRING::value_type(4,"Four"));
theMap.insert(INT2STRING::value_type(5,"Five"));
theMap.insert(INT2STRING::value_type(6,"Six"));
theMap.insert(INT2STRING::value_type(7,"Seven"));
theMap.insert(INT2STRING::value_type(8,"Eight"));
theMap.insert(INT2STRING::value_type(9,"Nine"));
for(;;)
{
cout<<"ENter \"q\" to quit,or enter a number:\n";
cin>>theString;
if(theString=="q")
break;
for(index=0;index<theString.length();index++){
theIterator=theMap.find(theString[index]-'0');
if(theIterator!=theMap.end())
cout<<(*theIterator).second<<" ";
else
cout<<"[err]";
}
cout<<endl;
}
return 1;
}