STL的本质就是:类模板,函数模板,运算符重载.说起来也是"多态"的表现形式,只不过具有高超的编程技巧和运用,能减少程序员的很多繁琐重复的工作,是一个优秀的"库".
STL提供六大组件,彼此可以组合套用,共同组合成STL丰富多彩的编程应用:
1)容器(containers):各种数据结构(基本上就是集合类.容器是STL的最主要的标志,可以浅显得认为STL就是容器类的集合...)
如:vector,list,deque,set,map,用来存放数据.
2)算法(algorithms):各种常用算法如:sort,search,copy,erase...
3)迭代器(iterator):
扮演容器与算法直接的胶合剂,所所谓的"泛型指针".(我靠,本质还是从指针来的,只不过"变异"了..)
共有5种类型,以及其他衍生变化:
4)仿函数(functors):行为类似函数,可作为算法的某种策略.(靠,其实就是类....)
仿函数是一种重载了operator()的class或class template,一般函数指针可看作为狭义的仿函数.
5)配接器(adapters):(其实就是C#中的接口啦!!!)
一种用来修饰容器(containers)或仿函数或迭代器接口的东西.
6)配置器(allocators):
负责空间配置与管理.
是一个实现了动态空间配置/空间管理/空间释放 的class template.
OK.STL就是容器类+算法实现+迭代器+配接器+仿函数+配置器.
容器通过配置器取得数据存储空间,算法通过迭代器存取容器内容,仿函数可以协助算法完成不同的策略变化,配接器可以修饰或套界仿函数.
以下着重说明STL的容器类以及一些基本的算法:
STL容器 所在头文件 特性
向量vector <vector> 相当于多功能数组,但是最好不要对向量头进行添加或删除操作
双端队列deque <deque> 基本与vector一样
表list <list> 对某一位置插入和删除操作花费小
队列queue <queue> 插入只可以在尾部,删除/检索和修改只能在头部.先进先出(与stack相反)
堆栈stack <stack> 后进先出
集合set <set> 每个节点包含一个元素,查找十分快速,不支持重复元素
多重集合multiset <set> 和集合基本相同,支持重复元素
映射map <map> 由键/值对组成的集合.(不能有重复键)
多重映射multimap <map> 可以有重复键.
很多功能,可以用不同的容器来实现(这点很重要),但是要考虑实际的需要,选择合适的容器将大大提高程序性能.(对于新手来说,嘿嘿,能用就好,用顺手了,好好比较下不同情况下不同容器实现相同功能的效率撒...)
STL算法:主要头文件<algorithm>,<numeric>,<functional>.
<algorithm>:由模板函数组成.常用功能算法:比较,交换,查找,遍历,复制,修改,移除,反转,排序,合并等.
<numeric>:包含几个在序列上进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作.
<functional>:定义了一些模板类,即仿函数.
STL迭代器:<iterator> (注意,可以把迭代器理解为指针,但是不能像指针一样使用迭代器...)
迭代器功能 功能 头文件
输入迭代器(Input iterator) 向前读 istream
输出迭代器(Output iterator) 向前写 ostream,inserter
前向迭代器(Forward iterator) 向前读写
双向迭代器 向前向后读写 list,set,vector,map,multimap,deque,queue
随即迭代器 随即读写 vector,deque,array,string
1)构造STL容器对象
#include <iostream>
#include <vector>
using namespace std;
class VS
{
public:
static void Show(vector<int> iv)
{
for(vector<int>::iterator iter=iv.begin(); iter!=iv.end(); iter++)
cout<<*iter<<endl;
cout<<"-----------------------------------------------"<<endl;
}
};
void main()
{
vector<int> iv1; //构造方法1,默认构造无元素,使用push_back方法向容器中添加元素
iv1.push_back(11);
iv1.push_back(222);
VS::Show(iv1);
vector<int> iv2(2); //构造方法2,构造2个int元素,默认初始值为0
VS::Show(iv2);
vector<int> iv3(3,1); //构造方法3,构造3个int元素,指定初始值为1
VS::Show(iv3);
int a[] = {1,2,343,542,22}; //构造方法4,从数组中直接构造容器元素
vector<int> iv4(a,a+5);
VS::Show(iv4);
vector<int> iv5(iv4); //构造方法5,从其他容器中直接构造本容器元素
VS::Show(iv5);
vector<int>::iterator iter = iv4.begin(); //构造方法6,使用迭带器指针构造
vector<int> iv6(iter+1,iter+3);
VS::Show(iv6);
cin.get();
}
//2)容器类的几种输出方式
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<typename T>
class print //仔细看了,print其实是一个类,只不过重载了"()"运算符,使用起来就像函数,所以称为"仿函数"
{
public:
void operator()(const T& elem)
{
cout<<elem<<" ";
}
};
void show(const vector<int>& iv)
{
for (int i=0; i<iv.size(); i++)
cout<<iv[i]<<" ";
cout<<endl<<"-----------------------------------"<<endl;
}
void display(const vector<int>& iv)
{
for (vector<int>::const_iterator iter=iv.begin(); iter!=iv.end(); iter++)
cout<<*iter<<" ";
cout<<endl<<"-----------------------------------"<<endl;
}
void main()
{
int ia[6] = {0,1,2,3,4,5};
vector<int> iv(ia,ia+6);
show(iv); //1)传统的索引输出
display(iv); //2)使用迭代器输出
for_each(iv.begin(),iv.end(),print<int>()); //3)使用for_each方法输出,需要配合自定义输出函数
cout<<endl<<"------------------------------------"<<endl;
copy(iv.begin(), iv.end(), ostream_iterator<int>(cout, " ")); //4)使用copy方法,调用系统输出函数
cin.get();
}
//3)STL算法:演示sort排序和reverse翻转(这两个方法配合,就可以实现从小到大和从大到小排序了)
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int a[10] = {12,0,5,3,6,8,9,34,32,18};
int b[5] = {5,3,6,8,9};
int d[15];
sort(a,a+10); //sort是从小到大排序,要实现从大到小排序,使用reverse方法翻转即可
for (int i=0; i<10; i++)
{
cout<<" "<<a[i];
}
cout<<endl;
sort(b,b+5); //b数组排序好,判断是否包含在排序好的a数组中
if(includes(a,a+10,b,b+5)) //includes方法判断一个数组是否是另一个数组的子集合...
cout<<"sorted b members are included in a.";//这里,可以发现数组a中也有"3,5,6,8,9"元素
else
cout<<"sorted a dosn't contain sorted b!";
cout<<endl;
reverse(a,a+10); //翻转
for (int i=0; i<10; i++)
{
cout<<" "<<a[i];
}
cout<<endl;
cin.get();
return 0;
}
//4)list列表容器,很常用的.
#include <iostream>
#include <list> //使用list容器,必须加此头文件
using namespace std;
void main()
{
list<int> pp; //声明int元素类型的list容器对象
for (int i=0; i<=9; i++)//后插
{
pp.push_back(i);//在当前list<int>容器的最后位置插上i的值
pp.push_front(i*i); //在头部插入元素
//insert() 在任意指定位置插入元素
}
//使用迭代器pi进行循环迭代输出pp容器中的所有元素
copy(pp.begin(),pp.end(),ostream_iterator<int>(cout," "));
cout<<endl<<"-----------------------------------------"<<endl;
//按常规做法进行迭代输出是不行的,因为list容器是用链表构建的,不支持随即访问功能(这点要注意)
//for (int i=0; i<pp.size(); i++)
//{
// cout<<pp[i]<<" ";
//}
cout<<pp.front()<<endl; //返回头元素
cout<<pp.back()<<endl; //返回尾元素
cout<<pp.size()<<endl; //显示此容器的所有元素个数
pp.pop_back(); //移除最后一个元素
pp.pop_front(); //移除最前一个元素
copy(pp.begin(),pp.end(),ostream_iterator<int>(cout," "));
cout<<endl<<"-----------------------------------------"<<endl;
cout<< pp.max_size()<<endl; //此list容器所能申请的最大空间
list<int>::iterator pi = pp.begin(); //声明迭代器pi,用来操纵list<int>容器对象
pp.assign(2,3); //assign是重新分配和构造的方法
copy(pp.begin(),pp.end(),ostream_iterator<int>(cout," "));
cout<<endl<<"-----------------------------------------"<<endl;
list<int> ppp;
cout<<ppp.empty()<<endl; //empty方法判断容器是否为空
cout<< pp.empty()<<endl; //可以发现ppp.empty()返回1,即"true",而pp容器因为有2个元素,返回0,"false"非空
cout<<pp.size()<<"clear方法清除前容器元素个数"<<endl;
pp.clear();
cout<<pp.size()<<"clear方法清除后容器元素个数"<<endl;
cin.get();
}
//5)list进一步
#include <iostream>
#include <list> //使用list容器,必须加此头文件
using namespace std;
template<class T>
void print_list(list<T>& p,string s)
{
list<T>::iterator iter;
for (iter=p.begin(); iter!=p.end(); iter++)
cout<<*iter<<" ";
for (string::iterator siter=s.begin(); siter!=s.end(); siter++)
cout<<*siter;
cout<<endl;
}
void main()
{
int ia[] = {1,2,45,6,2,3};
list<int> p1(ia,ia+6); //使用数组初始化list<int>容器对象
print_list(p1,"使用数组初始化list<int>容器对象");
list<int> p2(p1); //使用list<int>容器对象初始化list<int>容器对象
p2.push_front(101);
p2.push_back(1001);
print_list(p2,"使用list<int>容器对象初始化list<int>容器对象");
list<int> p3;
p3 = p2; //直接赋值
print_list(p3,"直接赋值");
list<int>::iterator iter = p3.begin();
p3.insert(iter,10000); //使用迭代器在指定位置插入10000
print_list(p3,"用迭代器在指定位置插入10000");
iter++; //这时iter指向p3容器的第2位置了
p3.insert(iter,3,111); //在p3的第2个位置,连续插入3个111
print_list(p3,"在p3的第2个位置,连续插入3个111");
p3.sort(); //进行排序,默认为升序
print_list(p3,"进行排序,默认为升序");
p3.reverse();
print_list(p3,"翻转容器元素,即sort和reverse方法相配合,达到了按降序排列的目的");
//list<int>容器p3与p2互相交换各自的值
//常规做法,利用一个中间量来进行转换,这里直接使用一个swap就可以完成目的了
p3.swap(p2);
print_list(p3,"与p2交换后的p3");
print_list(p2,"与p3交换后的p2");
p3.remove(1001); //移除指定元素值为1001
print_list(p3,"移除指定元素值为1001的p3");
p3.erase(p3.begin(),p3.end());
print_list(p3,"erase方法将指定区域内的容器元素全部清除");
cout<<p3.size()<<endl;
cin.get();
}