1 STL
1.1 通用算法(函数模板)
通用算法依赖迭代器实现,可以从头到尾遍历整个容器的方法for_each() find find_if count count_if sort copy
iterator find(pos_beg, pos_end, data)
iterator find_if(pos_beg, pos_end, cond), bool cond(element)
int count(...), int count_if(...)
#include<algorithm>
#include<iostream>
using namespace std;
template<typename T>
void print(T b, T e)
{
while( b != e)
cout << *b++ << endl;
}
class Person
{
string name;
int age;
public:
Person(const char* ch,int a):name(ch),age(a){}
friend bool operator<(const Person &a,const Person &b)
{
return a.age<b.age;
}
friend ostream& operator<<(ostream& os,const Person& p)
{
return os<< p.name << ":" << p.age;
}
};
int main()
{
Person p[3] = {{"furong",23},{"zengge",28},{"chunge",35}};
sort(p,p+3);
print(p,p+3);
return 0;
}
说明:STL中sort()函数模板默认使用“<”运算进行排序,重载类中的<运算符即可完成排序
1.2 容器(类模板)
a.标准容器:
(1)序列(顺序)式容器(vector是个能够存放任意类型的动态数组,能够增加和压缩数据;deque适合首尾删除增加;list链表)
(2)关联式容器(set不允许重复;multiset允许重复;map不允许重复;multimap允许重复)迭代器(内部类iterator,支持* -> ++ == !=),用来访问容器里的内容
插入迭代器,iostream迭代器,反向,const迭代器,
五种迭代器:输入,输出,前向,双向,随机访问迭代器
数组里面,指针是最原始的迭代器;每种容器都自己负责封装迭代器类
b.容器适配器(特殊容器):栈 队列 优先队列
c.函数对象(仿函数):对象能像函数一样使用,比如重载()运算符
d.内存分配器allocator
2 标准容器(类模板)共性
构造函数(包括无参构造,拷贝构造,区间构造(两个迭代器表示的两个位置))析构函数
迭代器相关函数:.begin()正向iterator,返回指向第一个元素位置的迭代器
.end()返回指向超越最后一个位置的迭代器
.rbegin()反向reverse_iterator,反向迭代器
.rend()
标准都支持 * -> == ++ -- = !=
插入:.insert(pos,element) 其中pos是个表示位置的迭代器
删除:.erase(pos), .erase(pos_beg,pos_end)
清除:.clear() 清除容器里所以的数据
大小:.size() .max_size()
交换:.swap(c2) .swap(c1,c2)
运算:= > < >= <= == !=
#include<vector>
#include<iostream>
#include<algorithm>
#include"print.h"
using namespace std;
int main()
{
//vector区间初始化
int a[7] = {12,45,67,59,98,67,89};
vector<int> v(a,a+7);
//迭代器(封装指针)输出
vector<int>::iterator b = v.begin();//声明迭代器
while(b != v.end())
cout << *b++ <<"\t";
cout << endl;
//sort()
sort(v.begin(),v.end());
cout << "vector排序后:" << endl;
print(v.begin(),v.end());
cout << "数组a内容:" << endl;
print(a,a+7);
//insert()插入方法为:在当前迭代器位置的前方插入
b = v.begin();
v.insert(b,128);
v.insert(v.end(),256);//128 12 45 59 67 67 89 98 256
//v.erase(++++b,b+4); 注意操作危险,vector动态管理内存,迭代器指向可能失效
v.erase(++v.begin(),++++v.begin());//删除方式:[ )
print(v.begin(),v.end());
//交换swap()
vector<int> vv(a+3,a+7);
vv.swap(v);
cout << "v:" ;
print(v.begin(),v.end());
cout << "vv:" ;
print(vv.begin(),vv.end());
return 0;
}
3 序列式共性vector deque list:
构造函数:增加了指定元素个数和初始值(初始值默认是0)
插入:.insert(pos,n,element) .insert(pos,pos_beg,pos_end)
赋值:.assign(n,element) .assign(pos_beg,pos_end) 旧的全部清理掉新的全部插入进来
调整:.resize(n,element=0)
首尾:.front(), .back() 可以修改首尾元素的值
增删:.push_back(element) .pop_back() 只删除,返回void
#include<list>
#include<iostream>
#include"print.h"
#include<string>
#include<deque>
using namespace std;
int main()
{
string str[5] = {"woshi","nihao","shide","haoren","yushi"};
list<string> lstr(5,"*");//默认为零初始化
lstr.insert(lstr.begin(),str,str+5);//区间插入
print(lstr.begin(),lstr.end());
deque<string> dstr(str,str+5);//区间初始化
dstr.insert(dstr.begin(),str+2,str+5);//区间插入
cout << "dstr = ";
print(dstr.begin(),dstr.end());
lstr.assign(5,"fuck you!");//覆盖赋值
lstr.assign(++lstr.begin(),++++++lstr.begin());//删掉了?
print(lstr.begin(),lstr.end());
lstr.resize(12,"love");//填充式扩展
print(lstr.begin(),lstr.end());
return 0;
}
3.1 vector个性
vector迭代器在插入删除之后可能会失效因为可能会重新分配内存,如果插入删除过再用迭代器需要重新去取得
当前容量:.capacity()
约定容量:.reserver(n)只要不超过这个容量就不用重新再分配,以免反复重新分配空间
下标[]: .operator[](i)不检查越界 .at(i)这个函数做越界检查,越界会抛出异常
#include<iostream>
#include<vector>
#include"print.h"
#include<typeinfo>
using namespace std;
int main()
{
//测试vector容量分配规律:1 2 4 8
vector<double> dv;
for(int i = 0;i < 10; i++)
{
dv.insert(dv.end(),i+0.1);
cout << "有效/容量:" << dv.size() << "/" <<dv.capacity()<<"\t";
}
cout << endl<< "约定容量:" << endl;
vector<double> dd;
dd.reserve(9);
for(int i = 0;i < 10; i++)
{
dd.insert(dd.end(),i+0.1);
cout << "有效/容量:" << dd.size() << "/" <<dd.capacity()<<"\t";
}
//测试越界访问检查
cout << endl<< "dv[10] = " << dv[10] << endl ;
try{
cout << "dv.at(10)" << dv.at(10) << endl;
}
catch(exception &e)
{
cout << "异常:" << e.what() <<endl;
cout << "类型:" << typeid(e).name()<< endl;
}
//vector二维动态数组
vector< vector<int> > vvi(5,vector<int>(3,128)); //注意 > >中间空格
vvi[1].assign(3,12);
vvi[4].assign(5,25);
for(int i = 0; i < vvi.size();i++)
{
for(int j = 0; j < vvi[i].size();j++)
cout << vvi[i][j] << " ";
cout << endl;
}
return 0;
}
3.2 deque的个性
下标[]: .operator[](i) 不检查越界, .at(i)越界抛异常
增删: .push_front(element), .push_back() .pop_front() .pop_back()
适合从前面插入或删除数据
3.3 list的个性(双向链表 )
增删:.push_front(element), .pop_front(), .remove(element)//==
不支持下标[]
除重:.unique()相邻的重复元素只保留一个
排序:.sort(compare_func=less)默认用小于符号比较,从小到大排序
倒置:.reverse()颠倒链表中元素顺序
转移:.splice(pos,list2), .splice(pos,list2,pos2), .splice (pos,list2,pos_beg,pos_end)
归并:.merge(list2)
#include<list>
#include<iostream>
#include"print.h"
using namespace std;
template<typename T>
bool compare(T a,T b)
{
return a/10 > b/20;
}
int main()
{
double dd[6] = {12.1,13.5,25.6,78.9,12.1,12.1};
list<double> ld(dd,dd+6);
//排序 指定大小顺序
ld.sort(greater<double>());
//排序 指定排序法则
ld.sort(compare<double>);
//除重 相邻的重复元素只保留一个
ld.unique();
print(ld.begin(),ld.end());
return 0;
}
4 关联式容器的共性 set<K>, multiset<K>, map<K,V>, multimap<K,V>
都是用二叉查找树实现的,都自动根据关键字排序
查找:.find(key)返回一个迭代器指向找到的第一个元素,失败返回.end()
统计:.count(key)统计关键字等于key的元素的个数
删除:.erase(key)删除关键字等于key的所有元素
区间:.lower_bound(key)取得关键字为key的第一个元素的位置, .upper_bound(key)取得关键字为key的最后一个元素之后的位置; .equal_range(key)一次取得关键字为key的元素的区间,返回一个pair
插入: .insert(element)
#include<set>
#include<iostream>
#include"print.h"
using namespace std;
//set类型:date
class date
{
int year;
int month;
int day;
public:
date(int y,int m,int d):year(y),month(m),day(d){};
friend bool operator<(date d1,date d2);
friend ostream& operator<<(ostream &os,const date &d);
};
//重载"<"运算符
bool operator<(date d1,date d2)
{
if(d1.year < d2.year) return 1;
else if(d1.year == d2.year)
{
if(d1.month < d2.month) return 1;
else if(d1.month == d2.month)
{
if(d1.day < d2.day) return 1;
else return 0;
}
else return 0;
}
else return 0;
}
//重载"<<"运算符
ostream& operator<<(ostream &os,const date &d)//形参2为临时变量
{
return os<< d.year << "-" << d.month << "-" << d.day;
}
int main()
{
multiset<date> md;
md.insert(date(1990,10,12));
md.insert(date(1990,10,12));
md.insert(date(1990,10,12));
md.insert(date(1991,1,12));
md.insert(date(1992,1,12));
md.insert(date(1992,1,12));
md.insert(date(1992,1,12));
md.insert(date(1991,4,12));
md.insert(date(1991,1,15));
print(md.begin(),md.end(),'\n');
//查找.find()
typedef multiset<date>::iterator MI;
MI it = md.find(date(1990,10,12));
if(it == md.end()) cout << "结果不存在!" << endl;
else cout << "发现目标:" << *it << endl;
//统计.count()
it = md.find(date(1990,10,12));
cout << "发现目标:" << md.count(*it) << "个" << endl;
//删除关键字项 .erase()
md.erase(date(1990,10,12));
print(md.begin(),md.end(),'\n');
cout << "************************" << endl;
//查找关键字区间
MI ib,ie;
ib = md.lower_bound(date(1992,1,12));
ie = md.upper_bound(date(1992,1,12));
print(ib,ie,'\n');
cout << "************************" << endl;
pair<MI,MI> p = md.equal_range(date(1992,1,12));
print(p.first,p.second,'\n');
return 0;
}
4.1 map的个性
不允许key重复 ,强调元素是map(key,value)一对
支持以key为下标访问对应的value的引用,如果key不存在就新增一个元素以这个为key,别的关联式容器不支持以Key为下标
如果存的强调是对应关系就用map,如果存的只是关心的数据不存在对应关系就用set,set把整个元素作为key来比较。
#include<map>
#include<iostream>
#include<string>
#include"print.h"
using namespace std;
int main()
{
map<int , string> mis;
//map插入方法,形参为pair或value_type
mis.insert(map<int,string>::value_type(1,"处女座"));
mis.insert(pair<int,string>(2,"天秤座"));
mis.insert(make_pair(3,"双子座"));
print(mis.begin(),mis.end(),'\n');
cout << "*************************" << endl;
//下标操作
mis[1] = "射手座";
//关键字插入处理
mis.insert(make_pair(3,"金牛座")); //关键字没有-插入,重复-不插入
print(mis.begin(),mis.end(),'\n');
return 0;
}
#ifndef _PRINT
#define _PRINT 1
#include<iostream>
using namespace std;
template<typename T>
void print(T b,T e,char c)
{
while(b != e)
cout << *b++ << c;
}
template<typename K,typename V>
ostream& operator<<(ostream& os, const pair<K,V>& p)
{
return os << p.first << ":" << p.second;
}
#endif
4.2 multimap的个性
允许重复key ,元素是(key/value)pair对,不支持方括号下标
#include<iostream>
#include<map>
#include<string>
#include"print.h"
using namespace std;
int main()
{
typedef multimap<string,int> MMSI;
typedef map<string,int> MSI;
MMSI mmsi;
MSI msi;
mmsi.insert(make_pair("春哥",1000));
mmsi.insert(make_pair("曾哥",2000));
mmsi.insert(make_pair("春哥",5000));
mmsi.insert(make_pair("曾哥",2000));
mmsi.insert(make_pair("春哥",5000));
mmsi.insert(make_pair("曾哥",2000));
mmsi.insert(make_pair("春哥",3000));
//print(mmsi.begin(),mmsi.end(),'\n');
//收入统计
MMSI::iterator ia,ib; //每个迭代器都是一个pair对
ia = mmsi.begin();
while(ia != mmsi.end())
{
int sum = 0;
string name = ia->first;
ib = mmsi.upper_bound(name);
while(ia != ib) sum += ia++->second;
msi.insert(make_pair(name,sum));
}
print(msi.begin(),msi.end(),'\n');
return 0;
}
4.3 set的个性
元素就是key, 不允许重复key,如果重复就会被抛弃,可以默认被排好序
#include<set>
#include<iostream>
#include<string>
#include<fstream>
#include"print.h"
using namespace std;
int main()
{
set<string> ss;
ifstream fin("strlist");
if(!fin)
{
cout << "打开文件失败" << endl;
return 1;
}
string s;
while(fin >> s) ss.insert(s); //去除相同项
print(ss.begin(),ss.end(),'\n');
return 0;
}
4.4 multiset的个性
元素就是key,允许有重复的key
#include<iostream>
#include<set>
#include<map>
#include<string>
#include"print.h"
using namespace std;
int main()
{
typedef multiset<string> MS;
typedef multimap<string,int> MSI;
MS ms;
MSI msi;
string name;
cout << "输入候选人名称(sky/moon/09): ctrl + d结束"<< endl;
while(cin >> name)
{
ms.insert(name);
}
MS::iterator ib = ms.begin(),ie;
while(ib != ms.end())
{
msi.insert(make_pair(*ib,ms.count(*ib)));
ib = ms.upper_bound(*ib);
}
print(msi.begin(),msi.end(),'\n');
return 0;
}
![](https://img-blog.csdn.net/20140502140920453)
#include<iostream>
#include<set>
#include<map>
#include<string>
#include"print.h"
using namespace std;
int main()
{
typedef multiset<string> MS;
typedef multimap<string,int> MSI;
MS ms;
MSI msi;
string name;
cout << "输入候选人名称(sky/moon/09): ctrl + d结束"<< endl;
while(cin >> name)
{
ms.insert(name);
}
MS::iterator ib = ms.begin(),ie;
while(ib != ms.end())
{
msi.insert(make_pair(*ib,ms.count(*ib)));
ib = ms.upper_bound(*ib);
}
print(msi.begin(),msi.end(),'\n');
return 0;
}