STL概述
STL组件
1.容器(Container) - 管理某类对象的集合
2.迭代器(Iterator) - 在对象集合上进行遍历
(注意:这些集合可能是容器,也可能是容器的子集。)
3.算法(Algorithm) - 处理集合内的元素,算法作用于容器。(算法提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作。)
4.容器适配器(container adaptor)
5.函数对象(functor)
(注意:STL容器的共同能力:
1.所有容器中存放的都是值而非引用。如果希望存放的不是副本,容器元素只能是指针。
2.所有元素都形成一个次序(order),可以按相同的次序一次或多次遍历每个元素)
STL类别
1.序列式容器-排列次序取决于插入时机和位置
2.关联式容器-排列顺序取决于特定准则
STL容器元素的条件
1.必须能够通过拷贝构造函数进行复制
2.必须可以通过赋值运算符完成赋值操作
3.必须可以通过析构函数完称销毁动作
4.序列式容器元素的默认构造函数必须可用
5.某些动作必须定义 operator==,例如搜寻操作
6.关联式容器必须定义出排序准则,默认情况是重载operator <
(对于基本数据类型(int,long,char,double,…)而言,以上条件总是满足)
STL容器的共同操作
初始化
1.产生一个空容器
std::list l;
2.以另一个容器元素为初值完成初始化
std::list l;
…
std::vector c(l.begin(),l.end())
3.以数组元素为初值完成初始化
int array[]={2,4,6,1345};
…
std::set c(array,array+sizeof(array)/sizeof(array[0]));
与大小相关的操作
1.size()-返回当前容器的元素数量
2.empty()-判断容器是否为空
3.max_size()-返回容器能容纳的最大元素数量
比较
1.==,!=,<,<=,>,>=
2.比较操作两端的容器必须属于同一类型
3.如果两个容器内的所有元素按序相等,那么这两个容器相等
4.采用字典式顺序判断某个容器是否小于另一个容器
赋值和交换
swap用于提高赋值操作效率
与迭代器相关的操作
1.begin()-返回一个迭代器,指向第一个元素
2.end()-返回一个迭代器,指向最后一个元素之后
3.rbegin()-返回一个逆向迭代器,指向逆向遍历的第一个元素
4.rend()-返回一个逆向迭代器,指向逆向遍历的最后一个元素之后
元素操作
1.insert(pos,e)-将元素e的拷贝安插于迭代器pos所指的位置
2.erase(beg,end)-移除[beg,end]区间内的所有元素
3.clear()-移除所有元素
迭代器
1.可遍历STL容器内全部或部分元素的对象
2.指出容器中的一个特定位置
3.迭代器的基本操作
迭代器分类
1.双向迭代器
可以双向行进,以递增运算前进或以递减运算后退、可以用==和!=比较。
list、set和map提供双向迭代器
list<int> l;
for(pos=l.begin();pos!=l.end();++pos{
…
}
2.随机存取迭代器
除了具备双向迭代器的所有属性,还具备随机访问能力。
可以对迭代器增加或减少一个偏移量、处理迭代器之间的距离或者使用<和>之类的关系运算符比较两个迭代器。
vector、deque和string提供随机存取迭代器
vector<int> v;
for(pos=v.begin();pos<v.end();++pos{
…
}
vector
1.vector模拟动态数组
2.vector的元素可以是任意类型T,但必须具备赋值和拷贝能力(具有public拷贝构造函数和重载的赋值操作符)
3.必须包含的头文件#include
4.vector支持随机存取
5.vector的大小(size)和容量(capacity)
(1)size返回实际元素个数,
(2)capacity返回vector能容纳的元素最大数量。如果插入元素时,元素个数超过capacity,需要重新配置内部存储器。
非变动操作
赋值操作
(注意:所有的赋值操作都有可能调用元素类型的默认构造函数,拷贝构造函数,赋值操作符和析构函数)
元素存取
迭代器相关函数
(注意: 迭代器持续有效,除非发生以下两种情况:
(1)删除或插入元素
(2)容量变化而引起内存重新分配)
安插元素
移除元素
map/multimap
概述
1.使用平衡二叉树管理元素
2.元素包含两部分(key,value),key和value可以是任意类型
3.必须包含的头文件#include
构造、拷贝和析构
(注意:其中map可以是下列形式:
map<key,value> 一个以less(<)为排序准则的map,
map<key,value,op> 一个以op为排序准则的map)
非变动性操作
赋值
特殊搜寻操作
迭代器相关函数
安插元素
移除元素
set/multiset
概述
1.使用平衡二叉树管理元素
2.集合(Set)是一种包含已排序对象的关联容器。
3.必须包含的头文件#include
4.map容器是键-值对的集合,好比以人名为键的地址和电话号码。相反地,set容器5.只是单纯的键的集合。当我们想知道某位用户是否存在时,使用set容器是最合适的。
6.set中不允许key相同的元素,multiset允许key相同的元素
基本操作
算法
泛型算法通则
1.所有算法的前两个参数都是一对iterators:[first,last),用来指出容器内一个范围内的元素。
2.每个算法的声明中,都表现出它所需要的最低层次的iterator类型。
count
size_t count(InIt first, InIt last, const T& val);
计算[first,last) 中等于val的元素个数
count_if
size_t count_if(InIt first, InIt last, Pred pr);
计算[first,last) 中符合pr(e) == true 的元素 e的个数
min_element
template
FwdIt min_element(FwdIt first, FwdIt last);
返回[first,last) 中最小元素的迭代器,以 “< ”作比较器
max_element
template
FwdIt max_element(FwdIt first, FwdIt last);
返回[first,last) 中最大(不小)元素的迭代器,以 “< ”作比较器
for_each
Fun for_each(InIt first, InIt last, Fun f);
对[first,last)中的每个元素 e ,执行 f(e) , 要求 f(e)不能改变e
find
template<class InIt, class T>
InIt find(InIt first, InIt last, const T& val);
返回区间 [first,last) 中的迭代器 i ,使得 * i == val
find_if
template<class InIt, class Pred>
InIt find_if(InIt first, InIt last, Pred pr);
返回区间 [first,last) 中的迭代器 i, 使得 pr(*i) == true
binary_search
(折半查找,要求容器已经有序且支持随机访问迭代器,返回是否找到)
1.template<class FwdIt, class T>
bool binary_search(FwdIt first, FwdIt last, const T& val);
上面这个版本,比较两个元素x,y 大小时, 看 x < y
2.template<class FwdIt, class T, class Pred>
bool binary_search(FwdIt first, FwdIt last, const T& val, Pred pr);
上面这个版本,比较两个元素x,y 大小时, 看 pr(x,y)
lower_bound,uper_bound, equal_range
lower_bound:
template<class FwdIt, class T>
FwdIt lower_bound(FwdIt first, FwdIt last, const T& val);
要求[first,last)是有序的,
查找大于等于val的最小的位置
uper_bound
template<class FwdIt, class T>
FwdIt upper_bound(FwdIt first, FwdIt last, const T& val);
要求[first,last)是有序的,
查找大于val的最小位置
equal_range
template<class FwdIt, class T>
pair<FwdIt, FwdIt> equal_range(FwdIt first, FwdIt last, const T& val);
要求[first,last)是有序的,
返回值是一个pair, 假设为 p, 则
[first,p.first) 中的元素都比 val 小
[p.second,last)中的所有元素都比 val 大
sort 快速排序
template
void sort(RanIt first, RanIt last);
按升序排序。判断x是否应比y靠前,就看 x < y 是否为true
template<class RanIt, class Pred>
void sort(RanIt first, RanIt last, Pred pr);
按升序排序。判断x是否应比y靠前,就看 pr(x,y) 是否为true
unique(改变序列)
1.template
FwdIt unique(FwdIt first, FwdIt last);
用 == 比较是否相等
2.template<class FwdIt, class Pred>
FwdIt unique(FwdIt first, FwdIt last, Pred pr);
用 pr 比较是否等
去除[first,last) 这个升序序列中的重复元素
返回值是迭代器,指向元素删除后的区间的最后一个元素的后面
reverse
template
void reverse(BidIt first, BidIt last);
颠倒区间[first,last)顺序
注意的点
1.push_back( ) 成员函数在向量的末尾插入值,如果有必要会扩展向量的大小。
2.size( ) 函数显示向量的大小。
3.begin( ) 函数返回一个指向向量开头的迭代器。
4.end( ) 函数返回一个指向向量末尾的迭代器。
5. string 中的 find函数
if(s1.find(s2)!=string::npos) 注意 其查找 是以s1的任何起点去找是否存在s2 如果是查找前缀字符串(一个字符串是另一个字符串的前缀) 如果这样找就可能超时
6.有时候出现弹窗 cannot read vs2005 是有提示的 而vc6是不提示的 原因之一可能是由于使用了没有赋值的变量导致指针乱飘了
一些实际应用
单个元素的查找
find() 比较条件为相等的查找
find()从给定区间中查找单个元素,定义:
int myints[] = { 10, 20, 30, 40 };
std::vector<int> myvector (myints,myints+4);
it = find (myvector.begin(), myvector.end(), 30);
if (it != myvector.end())
std::cout << "Element found in myvector: " << *it << '\n';
else
std::cout << "Element not found in myvector\n"
find_if() 自定义比较函数
std::find_if():从给定区间中找出满足比较函数的第一个元素;
示例,从myvector中查找能够被30整除的第一个元素:
bool cmpFunction (int i) {
return ((i%30)==0);
}
it = std::find_if (myvector.begin(), myvector.end(), cmpFunction);
std::cout << "first:" << *it <<std::endl;
利用find_if()函数结合map实现模糊查找
(注意:重载运算符是重点!!!)
首先对find_if函数的谓词函数进行改造:
template<class InIt, class Pred>
InIt find_if(InIt first, InIt last, Pred pr);
然后构造一个类,并重载函数运算符,在其内部实现取子串查找:
class map_value_finder
{
public:
map_value_finder(const string& cmp_string) :m_s_cmp_string(cmp_string) {}
bool operator ()(const multimap<string,int>::value_type& pair)
{
int loc;
loc=pair.first.find(m_s_cmp_string);
if (loc != pair.first.npos)
return true;
return false;
}
private:
const std::string& m_s_cmp_string;
};
void Operation::fuzzyFindBname(string str)
{
multimap<string, int>::iterator it,p1,p2,p;
p1 = bookname.begin();
p2 = bookname.end();
it = find_if(p1, bookname.end(), map_value_finder(str));
if (it == bookname.end())
return;
else
cout << book[it->second];
it++;
for (p = it; p != p2; p++)
{
it = find_if(p, bookname.end(), map_value_finder(str));
if (it == bookname.end())
return;
else
cout << book[it->second];
}
}
vector巧用swap收缩内存空间
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
using namespace std;
int main(){
vector<int> v;
for (int i = 0; i < 100000;i ++){
v.push_back(i);
}
cout << "capacity:" << v.capacity() << endl;
cout << "size:" << v.size() << endl;
//此时 通过resize改变容器大小
v.resize(10);
cout << "capacity:" << v.capacity() << endl;
cout << "size:" << v.size() << endl;
//容量没有改变
vector<int>(v).swap(v);
cout << "capacity:" << v.capacity() << endl;
cout << "size:" << v.size() << endl;
system("pause");
return EXIT_SUCCESS;
}
set的返回值
//插入操作返回值
void test01(){
set<int> s;
pair<set<int>::iterator,bool> ret = s.insert(10);
if (ret.second){
cout << "插入成功:" << *ret.first << endl;
}
else{
cout << "插入失败:" << *ret.first << endl;
}
ret = s.insert(10);
if(ret.second){
cout << "插入成功:" << *ret.first << endl;
}
else{
cout << "插入失败:" << *ret.first << endl;
}
}
struct MyCompare02{
bool operator()(int v1,int v2){
return v1 > v2;
}
};
//从大到小排序
void test02(){
srand((unsigned int)time(NULL));
//我们发现set容器的第二个模板参数可以设置排序规则,默认规则是less<_Kty>
set<int, MyCompare02> s;
for (int i = 0; i < 10;i++){
s.insert(rand() % 100);
}
for (set<int, MyCompare02>::iterator it = s.begin(); it != s.end(); it ++){
cout << *it << " ";
}
cout << endl;
}
学习心得
这一段时间我们学习了STL,感受就是既简单又复杂,说简单是因为STL的一个重要特点是数据结构和算法的分离。尽管这是个简单的概念,但这种分离确实使得STL变得非常通用,方便了我们的使用,使一些复杂问题可以通关简单的手段就能实现。说复杂是因为较难理解,有些地方比较绕,较难理解。有的时候理解了,运用到实例中时,却常常感到无从下手。近几天的学习状态不是很好,每天都感觉自己很忙,但是晚上入睡前回想总是感觉自己这一天啥也没干,啥也不是,状态很是浮躁。最近一段时间的生物钟也挺乱的,每天都不能按时吃饭睡觉,导致每天精神欠佳,迷迷糊糊的,这个星期开始调整自己的作息,找回自己的状态。