STL基础学习(STL中的容器解析、代码展示、例题分析,帮助你学STL)
STL就是Standard Template Library(C++标准模板库),下面是关于STL中的各种内容
STL中的几个基本概念:
1.容器:可容纳各种数据类型的数据结构。
可以用于存放各种类型的数据(基本类型的变量,对象等)的数据结构。
容器分为三大类:
(1) 顺序容器
vector:后部插入/删除,直接访问 deque:前/后部插入/删除,直接访问 list:双向链表,任意位置插入/删除
1) vector 头文件 <vector>
实际上就是个动态数组。随机存取任何元素都能在常数时间完成。在尾端增删元素具有较佳的性能。
2) deque 头文件 <deque>
也是个动态数组,随机存取任何元素都能在常数时间完成(但性能次于vector)。在两端增删元素具有较佳的性能。
3) list 头文件 <list>
双向链表,在任何位置增删元素都能在常数时间完成。不支持随机存取。
上述三种容器称为顺序容器,是因为元素的插入位置同元素的值无关。
( 2)关联容器
set:快速查找,无重复元素 multiset :快速查找,可有重复元素 map:一对一映射,无重复元素,基于关键字查找 multimap :一对一映射,可有重复元素,基于关键字查找,前2者合称为第一类容器
关联式容器内的元素是排序的,插入任何元素,都按相应的排序准则来确定其位置。关联式容器的特点是在查找时具有非常好的性能。
1) set/multiset: 头文件 <set>
set 即集合。set中不允许相同元素,multiset中允许存在相同的元素。
2) map/multimap: 头文件 <map>
map与set的不同在于map中存放的是成对的key/value。
并根据key对元素进行排序,可快速地根据key来检索元素
map同multimap的不同在于是否允许多个元素有相同的key值。
上述4种容器通常以平衡二叉树方式实现,插入和检索的时间都是 O(logN)
(3)容器适配器
stack:LIFO queue:FIFO priority_queue:优先级高的元素先出
对象被插入容器中时,被插入的是对象的一个复制品。
许多算法,比如排序,查找,要求对容器中的元素进行比较,所以,放入容器的对象所属的类,还应该实现 == 和 < 运算符。
1) stack :头文件 <stack>
栈。是项的有限序列,并满足序列中被删除、检索和修改的项只能是最近插入序列的项。即按照后进先出的原则
2) queue :头文件 <queue>
队列。插入只可以在尾部进行,删除、检索和修改只允许从头部进行。按照先进先出的原则。
3)priority_queue :头文件 <queue>
优先级队列。最高优先级元素总是第一个出列
所有标准库容器共有的成员函数:
相当于按词典顺序比较两个容器大小的运算符: =, < , <= , > , >=, == , !=
empty : 判断容器中是否有元素
max_size: 容器中最多能装多少元素
size: 容器中元素个数
swap: 交换两个容器的内容
只在第一类容器中的函数:
begin 返回指向容器中第一个元素的迭代器
end 返回指向容器中最后一个元素后面的位置的迭代器
rbegin 返回指向容器中最后一个元素的迭代器
rend 返回指向容器中第一个元素前面的位置的迭代器
erase 从容器中删除一个或几个元素
clear 从容器中删除所有元素
2.迭代器:可依次存取容器中元素的东西
用于指向第一类容器中的元素。有const 和非 const两种。
通过迭代器可以读取它指向的元素,通过非const迭代器还能修改其指向的元素。迭代器用法和指针类似。
定义一个容器类的迭代器的方法可以是:
容器类名::iterator 变量名;
或:
容器类名::const_iterator 变量名;
访问一个迭代器指向的元素:
* 迭代器变量名
迭代器上可以执行 ++ 操作, 以指向容器中的下一个元素。如果迭代器到达了容器中的最后一个元素的后面,则迭代器变成past-the-end值。
使用一个past-the-end值的迭代器来访问对象是非法的,就好像使用NULL或未初始化的指针一样。
算法:用来操作容器中的元素的函数模板。例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象。
函数本身与他们操作的数据的结构和类型无关,因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用。
比如,数组int array[100]就是个容器,而 int * 类型的指针变量就可以作为迭代器,可以为这个容器编写一个排序的算法,以下是各种算法:
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<int> v; //一个存放int元素的向量,一开始里面没有元素
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
vector<int>::const_iterator i; //常量迭代器
for( i = v.begin();i != v.end();i ++ )
cout << * i << ",";
cout << endl;
vector<int>::reverse_iterator r; //反向迭代器
for( r = v.rbegin();r != v.rend();r++ )
cout << * r << ",";
cout << endl;
vector<int>::iterator j; //非常量迭代器
for( j = v.begin();j != v.end();j ++ )
* j = 100;
for( i = v.begin();i != v.end();i++ )
cout << * i << ",";
}
输出结果:
1,2,3,4,
4,3,2,1,
100,100,100,100,
STL 中的迭代器按功能由弱到强分为5种:
1. 输入:Input iterators 提供对数据的只读访问。
1. 输出:Output iterators 提供对数据的只写访问
2. 正向:Forward iterators 提供读写操作,并能一次一个地向前推进迭代器。
3. 双向:Bidirectional iterators提供读写操作,并能一次一个地向前和向后移动。
4. 随机访问:Random access iterators提供读写操作,并能在数据中随机移动。
编号大的迭代器拥有编号小的迭代器的所有功能,能当作编号小的迭代器使用。
不同迭代器所能进行的操作(功能):
所有迭代器: ++p, p ++
输入迭代器: * p, p = p1, p == p1 , p!= p1
输出迭代器: * p, p = p1
正向迭代器: 上面全部
双向迭代器: 上面全部,--p, p --,
随机访问迭代器: 上面全部,以及:
p+= i, p -= i,
p + i: 返回指向 p 后面的第i个元素的迭代器
p - i: 返回指向 p 前面的第i个元素的迭代器
p[i]: p 后面的第i个元素的引用
p < p1, p <= p1, p > p1, p>= p1
容器所支持的迭代器类别:
容器 迭代器类别
vector
随机
deque 随机
list 双向
set/multiset
双向
map/multimap
双向
stack 不支持迭代器
queue 不支持迭代器
priority_queue
不支持迭代器
例如,vector的迭代器是随机迭代器,所以遍历 vector 可以有以下几种做法:
vector<int> v(100);
vector<int>::value_type i; //等效于写 int i;(P687)
for(i = 0;i < v.size() ; i ++)
cout << v[i];
vector<int>::const_iterator ii;
for( ii = v.begin(); ii != v.end ();ii ++ )
cout << * ii;
//间隔一个输出:
ii = v.begin();
while( ii < v.end()) {
cout << * ii;
ii = ii + 2;
}
而 list 的迭代器是双向迭代器,所以以下代码可以:
list<int> v;
list<int>::const_iterator ii;
for( ii = v.begin(); ii != v.end ();ii ++ )
cout << * ii;
以下代码则不行:
for( ii = v.begin(); ii < v.end ();ii ++ )
cout << * ii;
//双向迭代器不支持 <
for(int i = 0;i < v.size() ; i ++)
cout << v[i]; //双向迭代器不支持 []
例子:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
main() {
int array[10] = {10,20,30,40};
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
vector<int>::iterator p;
p = find(v.begin(),v.end(),3);
if( p != v.end())
cout << * p << endl;
p = find(v.begin(),v.end(),9);
if( p == v.end())
cout << "not found " << endl;
p = find(v.begin()+1,v.end()-2,1);
if( p != v.end())
cout << * p << endl;
int * pp = find( array,array+4,20);
cout << * pp << endl;
}
输出:
3
not found
3
20
例:
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,
例:
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, istream_iterator的例子
int main() {
istream_iterator<int> inputInt(cin);
int n1,n2;
n1 = * inputInt; //读入 n1
inputInt ++;
n2 = * inputInt; //读入 n2
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 0;
}
程序运行后输入 78 90敲回车,则输出结果为:
78,90
168
12345
例';
#include <set>
#include <iostream>
using namespace std;
int main() {
typedef set<double,less<double> > double_set;
const int SIZE = 5;
double a[SIZE] = {2.1,4.2,9.5,2.1,3.7 };
double_set doubleSet(a,a+SIZE);
ostream_iterator<double> output(cout," ");
cout << "1) ";
copy(doubleSet.begin(),doubleSet.end(),output);
cout << endl;
pair<double_set::const_iterator, bool> p;
p = doubleSet.insert(9.5);
if( p.second )
cout << "2) " << * (p.first) << " inserted" << endl;
else
cout << "2) " << * (p.first) << " not inserted" << endl;
return 0; }
输出:
1) 2.1 3.7 4.2 9.5
2) 9.5 not inserted
#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;
}
输出:
1) 0
2) 1
3) (15,2.7),(20,9.3),
4) (15,2.7),(20,9.3),(40,0),
5) (15,6.28),(20,9.3),(40,0),
如何用程序用来统计一篇英文文章中单词出现的频率(为简单起见,假定依次从键盘输入该文章)
#include <iostream
> #include <map>
using namespace std;
int main() {
map<string, int> wordCount;
string word;
while (cin >> word)
++wordCount[word];
for (map<string, int>::iterator it = wordCount.begin(); it != wordCount.end(); ++it)
cout<<"Word: "<<(*it).first<<" \tCount: "<<(*it).second<<endl;
return 0; }
例:
#include <queue>
#include <iostream>
using namespace std;
int main() {
priority_queue<double> priorities;
priorities.push(3.2);
priorities.push(9.8);
priorities.push(5.4);
while( !priorities.empty() ) {
cout << priorities.top() << " "; priorities.pop();
}
return 0;
}
//输出结果:9.8 5.4 3.2
例:
int main() {
const int SIZE = 10;
int a1[] = { 2,8,1,50,3,100,8,9,10,2 };
vector<int> v(a1,a1+SIZE);
ostream_iterator<int> output(cout," ");
vector<int>::iterator location;
location = find(v.begin(),v.end(),10);
if( location != v.end()) {
cout << endl << "1) " << location - v.begin();
}
sort(v.begin(),v.end());
if( binary_search(v.begin(),v.end(),9))
cout << endl << "3) " << "9 found";
else
cout << endl << " 3) " << " 9 not found";
return 0;
}
输出:(无sort语句)
1) 8
2) 3
3) 9 not found
输出: (有sort语句)
1) 8
2) 3
3) 9 found