S T L
Standard Template Libarary--标准模板库
STL由一些可适应不同需求的集合类(collection class),以及在这些数据集合上操作的算法(algorithm)构成
STL内的所有组件都由模板(template)构成,其元素可以是任意类型
STL是所有C++编译器和所有操作系统平台都支持的一种库
概述
STL组件
l 容器(container)—管理某类对象的集合
l 迭代器(iterator)—在对象集合上进行遍历。
l 算法(Algorithm) - 处理集合内的元素
l 容器适配器(container adaptor)
l 函数对象(functor)
关系图:
容器
容器类别
1,序列式容器:排列次序取决于插入时机和位置
例如:vector ,list ,queue,,,,
2,关联式容器:排列顺序取决于特定准则
例如:map ,set ,,,,
容器的共同能力
1,所有容器中存放的都是值而非引用。如果希望存放的不是副本,容器元素只能是指针。
2,所有元素都形成一个次序,可以按相同的次序一次或多次遍历每个元素。
容器元素的所有条件
1,必须能够通过拷贝构造函数进行复制,
2,必须可以通过赋值运算符完成赋值操作,
3,必须可以通过析构函数完成销毁动作,
4,序列式容器元素的默认构造函数必须可用
5,某些动作必须定义operator ==,例如搜寻操作
6,关联式容器必须定义出排序准则,默认情况是重载operator<
容器的共同操作
1,初始化,建立产生一个空容器
2,进行数据初始化
//或者,以另一个容器元素为初值完成初始化
//或者,以数组元素为初值完成初始化
容器的共同操作
1,与大小相关的操作
l sizeof()—返回当前容器元素的数量
l empty()—判断当前容器是否为空容器
3)max_size()—返回容器能容纳的最大元素的数量
2,与比较相关的操作
l == , != , < , <= , >=
l 比较操作两端的数据必须属于同一类型
l 如果两个容器内的元素按序相等,则这两个容器相同
l 采用字典式顺序判断一个容器是否小于另一个容器
3,与赋值有关的操作
l 复制和交换,Swap用于提高赋值操作的效率
4,元素的操作
l insert(pos,e)—将元素e的拷贝安插于迭代器pos所指的位置
l erase(begin(),end())—移除[begin(),end())之间的元素
注:end()表示最后一个元素的下一个位置
l clear()—移除所有元素
迭代器
可遍历STL容器内全部或部分元素的对象,指出容器中的一个特定位置。
基本操作
l * :返回当前位置上的元素值,如果该元素有成员,可以通过迭代器operator->取用
l ++ :将迭代器前进至下一个元素
l == 和 != :判断两个迭代器是否指向同一个位置
l == :为迭代器赋值
l begin() :返回一个迭代器,指向第一个元素
l end():返回一个迭代器,指向最后一个元素之后
注:[begin,end)是半开区间的好处:
l 为遍历元素时循环的结构时机提供了简单的判断依据(只要未到end(),循环就可以继续)
l 不必对空区间采取特殊处理(空区间的begin(),就等于end())
提供两种不同的迭代器
container(容器)::iterator it 以读/写模式遍历元素
container(容器)::const_iterator it 以只读模式遍历元素
迭代器的分类
1,双向迭代器:可以双向进行,以递增运算前进或以递减运算后退、可以用==和!=比较
list、set和map提供双向迭代器
2,随机存取迭代器
l 除了具备双向迭代器的所有属性,还具备随机访问能力
l 可以对迭代器增加或减少一个偏移量处理迭代器之间的距离,或者使用<>之类的关系运算符比较两个迭代器
算法
常用算法:
l binary_search: 在有序序列中查找value,找到返回true。重载的版本实用指定的比较函数对象或函数指针来判断相等。
l count: 利用等于操作符,把标志范围内的元素与输入值比较,返回相等元素个数。
l count_if: 利用输入的操作符,对标志范围内的元素进行操作,返回结果为true的个数。
l find: 利用底层元素的等于操作符,对指定范围内的元素与输入值进行比较。当匹配时,结束搜索,返回该元素的一个InputIterator。
l find_if: 使用输入的函数代替等于操作符执行find。
l lower_bound: 返回一个ForwardIterator,指向在有序序列范围内的可以插入指定值而不破坏容器顺序的第一个位置。重载函数使用自定义比较操作。
l upper_bound: 返回一个ForwardIterator,指向在有序序列范围内插入value而不破坏容器顺序的最后一个位置,该位置标志一个大于value的值。重载函数使用自定义比较操作。
l search: 给出两个范围,返回一个ForwardIterator,查找成功指向第一个范围内第一次出现子序列(第二个范围)的位置,查找失败指向last1。重载版本使用自定义的比较操作。
l sort: 以升序重新排列指定范围内的元素。重载版本使用自定义的比较操作。
l stable_sort: 与sort类似,不过保留相等元素之间的顺序关系。
l swap: 交换存储在两个对象中的值。
l next_permutation: 取出当前范围内的排列,并重新排序为下一个排列。重载版本使用自定义的比较操作。
l prev_permutation: 取出指定范围内的序列并将它重新排序为上一个序列。如果不存在上一个序列则返回false。重载版本使用自定义的比较操作。
l fill: 将输入值赋给标志范围内的所有元素。
l fill_n: 将输入值赋给first到first+n范围内的所有元素。
l for_each: 用指定函数依次对指定范围内所有元素进行迭代访问,返回所指定的函数类型。该函数不得修改序列中的元素。
l max: 返回两个元素中较大一个。重载版本使用自定义比较操作。
l min: 返回两个元素中较小一个。重载版本使用自定义比较操作。
具体算法内容查看博客,详细了解算法实现单独查看资料
https://blog.csdn.net/robin__chou/article/details/53204970
vector
功能
1,vector模拟动态数组,(默认100个元素)
2,vector的元素可以是任意类型T,但必须具备赋值和拷贝能力(具有public拷贝构造函数和重载的赋值操作符)
3,必须包含的头文件#include<vector>
4,vector支持随机存取
5,vector的大小(size)和容量(capacity)
l Size返回实际元素的个数
l Capacity返回vector能容纳的元素的最大数量。如果插入元素时,元素个数超过capacity,需要重新配置内部存储器
相关操作
l vector<T>c 产生空的vector
l vector<T>c1 (c2) 产生同类型的c1,并将复制c2的所有元素
l vector<T>c(n)利用类型T的默认构造函数和拷贝构造函数生成一个大小为n的vector
l vector<T>c(n,e) 产生一个大小为n的vector,每个元素都是e
l vector<T>c(beg,end) 产生一个vector,以区间[beg,end)为元素初值
l ~vector<T>() 销毁所有元素并释放内存
l c.size() 返回元素个数
l c.empty() 判断容器是否为空
l c.max_size() 返回元素最大数量
l c.capacity() 返回重新分配空间可容纳的最大元素数量
l c.reverse(n) 扩大容量为n
l c1==c2 判断c1是否等于c2(其他的运算符也是这样操作)
l c1=c2 强c2的全部元素赋值给c1
l c.assign(n,e) 将元素e的n个拷贝赋值给c
l c1.swap(c2) 将c1和c2的元素互换
Swap(c1,c2)全局函数 c1,c2元素互换
l c.assign(x.begin(),x.end()) 将x的区间begin()和 end()之间的元素都赋值给c
l begin() 返回一个迭代器,指向第一个元素
rbegin() 返回一个逆向迭代器,指向逆向遍历的第一个元素
l end() 返回一个迭代器,指向最后一个元素之后
rend() 返回一个逆向迭代器,指向逆向遍历的最后一个元素之
//注:pos为迭代器返回位置
l c.insert(pos,e) 在pos位置插入元素e的副本,并返回新元素的位置
l c.insert(pos,n,e)在pos位置插入n个e的副本
l c.insert(pos,begin(),end())在pos位置从插入区间[beg,end]内所有元素的副本
l push_back(e)在尾部添加一个元素e的副本
l c.pop_back() 移除最后一个元素但不返回最后一个元素
l c.erase(pos) 移除pos位置的元素,返回下一个元素的位置
l c.erase(begin(),end()) 删除beg和end之间所有元素,返回下一个元素的位置
l c.clear() 删除所有元素,清空容器
Vector应用实例:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
vector<int>a;//建立容器
for(int i = 0; i <5; ++i)
{
a.push_back(5 -i);//存储数据
}
cout <<"Size: " << a.size() << endl;//输出实际大小
a.pop_back();//删除尾元素
a[0] = 1;//赋值
cout <<"Size: " << a.size() << endl;
for(int i = 0; i <(int)a.size(); ++i)
{
cout <<a[i] << ", ";
}
cout << endl;
sort(a.begin(),a.end());//排序
cout <<"Size: " << a.size() << endl;
for(int i = 0; i <(int)a.size(); ++i)
{
cout <<a[i] << ", ";
}
cout << endl;
a.clear();//清空
cout <<"Size: " << a.size() << endl;
return 0;
}
map/multimap
l 使用平衡二叉树管理元素
l 元素包含两部分(key,vaule) key和vaule可以是任意类型
注:key是要存放元素的关键字,vaule是要查找的元素
l 必须包含头文件#include<map>
l 根据元素key自动对元素排序,因此根据元素key对元素定位很快,但根据元素vaule对元素定位很慢,
l 不能直接改变元素的key,可以通过operator[](重载[])直接存取元素的值
l map中不允许key相同的元素,multimap允许key相同的元素
常见的map/multimap中的函数
l map c 产生空的map
l map c1(c2) 产生同类型的c1,并复制c2的所有元素
l map c(op) 以op为排序准则,产生一个空的map
l map c(begin(),end()) 以区间元素产生一个空的map
l map c(begin(),end(),op) 以op为排序准则,以区间内的元素产生一个空的map
l ~map 销毁所有元素,并释放内存
注:map可以是以下形式
a) map(key,vaule) 一个以less(<)(默认)为排序准则的map
b) map(key,vaule,op) 一个以op为排序准则的map
l c.size() 返回元素个数
l c.empty()判断容器是否为空
l c.max_size() 返回元素最大可能数量
l c1==c2 判断c1是否等于c2(其他运算符用法一样)
l c1=c2 将c2的元素全部复制给c1
l count(key) 记录返回满足条件的元素个数
l find(key) 返回值等于key的第一个元素,找不到则返回end
l lower_bound(key) 返回满足条件的第一条记录
l upper_bound(key) 返回满足条件的最后一条记录的下一个位置
l equal_range(key) 返回值等于key的区间
l begin() 返回一个双向迭代器,并指向第一个元素
l end() 返回一个双向迭代器,并指向最后一个元素的下一个位置
注:其他函数用法与vector差不多
样例:
map应用实例
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
struct T1
{
int v;
bool operator <(const T1 &a)const
{
return (v <a.v);
}
};
struct T2
{
int v;
};
struct cmp
{
bool operator () (const T2 &a, const T2&b)const
{
return (a.v <b.v);
}
};
int main()
{
map<T1,int>mt1;
map<T2, int,cmp>mt2;
map<string,int> m2;
map<string,int>::iterator m2i, p1, p2;
//map<string, int,greater<string> >m2;//greater<string>默认小大排序
//map<string, int,greater<string> >::iterator m2i, p1, p2;//迭代器
m2["abd"] =2;
m2["abc"] =1;
m2["cba"] =2;
m2.insert(make_pair("aaa", 9));
//make_pair 属于算法的内容,将两盒数组合成整体
m2["abf"] =4;
m2["abe"] =2;
cout <<m2["abc"] << endl;
m2i=m2.find("cba");
if(m2i != m2.end())
{
cout <<m2i->first << ": " <<m2i->second << endl;
}
else
{
cout <<"find nothing" << endl;
}
cout <<"Iterate" << endl;
for(m2i = m2.begin();m2i != m2.end(); m2i++)
{
cout <<m2i->first << ": " <<m2i->second << endl;
}
return 0;
}
multimap应用实例
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
int main()
{
multimap<string,int> mm1;
multimap<string,int>::iterator mm1i, p1, p2;
mm1.insert(make_pair("b", 3));
mm1.insert(make_pair("a", 0));
mm1.insert(make_pair("b", 5));
mm1.insert(make_pair("c", 4));
mm1.insert(make_pair("b", 2));
cout <<"Size: " << mm1.size() << endl;
for(mm1i =mm1.begin(); mm1i != mm1.end(); mm1i++)
{
cout <<mm1i->first << ": " <<mm1i->second << endl;
}
cout <<"COUNT: " << mm1.count("b")<< endl;//b 的个数
cout <<"Bound: " << endl;
p1=mm1.lower_bound("b");
p2=mm1.upper_bound("b");
for(mm1i = p1; mm1i!= p2; mm1i++)
{
cout <<mm1i->first << ": " <<mm1i->second << endl;
}
return 0;
}
set/multiset
l 使用平衡二叉树管理元素,集合(set)是一种包含以排序对象的关联容器
l 必须包含头文件#include<set>
注:map容器是键-值对的集合,好比以人名为关键字的地址和电话号码,相反的,set容器只是单纯的关键字的集合,当我们想知道某位用户是否存在时,使用set容器是最合适的
l set容器中不允许key相同的元素,multiset可以相同
注:set中只存放一个关键字,而multiset中可以存放很多个
常见函数
l get_allocator() 返回集合的分配器
l value_comp() 返回一个用于比较元素间的值的函数
其余与multimap中的常见函数类似,,可对比使用
pair模板
l pair模板可以用于生成key-value对
样例:
#include<iostream>
#include <set>
#include<algorithm>
using namespace std;
struct T1
{
int key;
int value1, value2;
bool operator<(const T1 &b)const
{
return (key < b.key);
}
};
struct T2
{
int key;
int v1, v2;
};
struct T2cmp
{
bool operator()(const T2 &a, const T2&b)const
{
return (a.key < b.key);
}
};
int main()
{
multiset<T1> s2;
multiset<T2, T2cmp> s3;
multiset<string>s1;
multiset<string>::iterator iter1;
//multiset<string, greater<string>>s1;//默认的小大排序形式
//multiset<string, greater<string>>::iterator iter1;
s1.insert("abc");
s1.insert("abc");
s1.insert("abc");
s1.insert("bca");
s1.insert("aaa");
cout << "ITERATE:" <<endl;
for(iter1 = s1.begin(); iter1 != s1.end();iter1++)
{
cout << (*iter1) << endl;
}
cout << "FIND:" <<endl;
iter1 = s1.find("abc");
if(iter1 != s1.end())
{
cout << *iter1 << endl;
}
else
{
cout << "NOT FOUND"<< endl;
}
cout << "COUNT: " <<s1.count("abc")<< endl;//个数
cout << "BOUND: " <<endl;
multiset<string>::iterator s1i, p1,p2;
p1= s1.lower_bound("abc");
p2= s1.upper_bound("abc");
for(s1i = p1; s1i != p2; s1i++)
{
cout << (*s1i) << endl;
}
return 0;
}
心得体会
STL最大的功能就是提供强大并且简单的功能函数,是我们的代码看起来简洁,易懂,条例清晰,方便了一些操作;
对于容器来说,给人的感觉就是,这些容器共同组成了一本书,vector是数的内容,map和set共同组成了书的目录这几者相辅相成,共同完成任务。