类模板构成容器 函数模板构成算法
1)迭代器(it):++,*,->,==,!=
输入迭代器:可读*it的值,但不一定能修改(设置)*it的值
输出迭代器:可以设置*it的值,但不一定能读取*it的值
前向迭代器:可以读取也可以设置*it的值
双向迭代器:支持--
随机迭代器:几乎跟指针一样,支持--,+n,-n,比较大小,[下标]
2)适配器:是使一事物的行为类似于另一事物的行为的一种机制,包括容器适配器,迭代器适配器和函数适配器。
3)函数模板(通用算法algorithm)--->关于算法的 查找 排序
内容太多,通用算法依赖迭代器实现,可以从头到尾遍历整个容器的方法
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(...)
01sort.cpp
#include <string>
#include <algorithm> //sort排序算法需要的头文件
class Person
{
string name;
int age;
public:
Person(const char* name, int age):name(name),age(age){}
friend ostream&operator<<(ostream&o,const Person&p)
{
return o<<p.name<<':'<<p.age;
}
friend bool operator<(const Person& a,const Person& b)
{
return a.age<b.age;
}
};
template<typename T>
void print(T b, T e)
{
while(b!=e)
cout << *b++ << ' ';
cout << endl;
}
int main()
{
int a[6]={8,1,6,3,2,5};
double b[4]={5.5,3.3,6.6,2.2};
string c[5]={"nice","to","see","you","all"};
Person d[3]= {Person("芙蓉",18),Person("杨强",20),Person("薇薇",16)};
sort(a,a+6);sort(b,b+4);sort(c,c+5);sort(d,d+3);
print(a,a+6);print(b,b+4);print(c,c+5);print(d,d+3); //半开区间 [)含头不含尾
return 0;
}
4)类模板(容器containter)---->关于数据结构 数组 链表 栈 队列 二叉树
a.标准容器:序列(顺序)式容器(vector是个能够存放任意类型的动态数组,能够增加和压缩数据;deque适合首尾删除增加;list链表)
关联式容器(set不允许重复;multiset允许重复;map不允许重复;multimap允许重复)
迭代器(标准容器类都有一个内部类iterator,支持* -> ++ == !=),用来访问容器里的内容
插入迭代器,iostream迭代器,反向,const迭代器,
五种迭代器:输入,输出,前向,双向,随机访问迭代器
迭代器是封装成类的指针,数组里面,指针是最原始的迭代器
每种容器都自己负责封装迭代器类
b.容器适配器(特殊容器):栈 队列 优先队列
c.函数对象:(仿函数)对象能像函数一样使用,比如重载()运算符
d.内存分配器allocator
标准容器(类模板)共性://特殊容器不支持下面操作
构造函数(包括无参构造,拷贝构造,区间构造(两个迭代器表示的两个位置))
析构函数
迭代器相关函数:
iterator,reverse_iterator,const_iterator,const_reverse_iterator
.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)(通用算法也就是函数)
运算:= > < >= <= == !=
02container.cpp
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include "print.h"
int main()
{
int a[5]={33,22,11,55,44};
vector<int> vi(a,a+5);
cout << vi.size() << endl;
sort(vi.begin(), vi.end());//只能是数组、vector和deque
vector<int>::iterator b = vi.begin();
while(b!=vi.end())
cout << *b++ << ' ';
cout << endl;
for(int i=0; i<5; i++)
cout << a[i] << ',';
cout << endl;
print(vi.begin(), vi.end());
print(a, a+5);
print(vi.rbegin(), vi.rend());
b = vi.begin();
vi.insert(++++b,66);
vi.insert(vi.begin(), 77);
vi.insert(vi.end(),88);
print(vi.begin(), vi.end());
cout << vi.size() << '/' << vi.max_size() << endl;
vi.erase(------vi.end());
print(vi.begin(), vi.end());
vi.erase(++++vi.begin(),--vi.end());
print(vi.begin(), vi.end());
vector<int> v2(a,a+5);
print(v2.begin(), v2.end());
cout << "==================" << endl;
vi.swap(v2);
print(vi.begin(), vi.end());
print(v2.begin(), v2.end());
cout << "==================" << endl;
swap(vi,v2);
print(vi.begin(), vi.end());
print(v2.begin(), v2.end());
cout << "==================" << endl;
vector<int> t=vi;
vi = v2;
v2 = t;
print(vi.begin(), vi.end());
print(v2.begin(), v2.end());
vi.clear();
cout << vi.size() << endl;
print(vi.begin(), vi.end());
vector<int> x;
cout << "vector当前容量:" << x.capacity() << endl;
}
print.h
#ifndef PRINT_H
#define PRINT_H 1
//输出一个指定区间中的所有数据(含头不含尾)
template<typename T>
void print(T b, T e, char c=' ')
{
while(b!=e)
cout << *b++ << c;
cout << endl;
}
#endif
————————————————————————————————————————
序列式容器共性vector deque list:
构造函数:增加了指定元素个数和初始值(初始值默认是0)
插入:.insert(pos,n,element) .insert(pos,pos_beg,pos_end)
赋值:.assign(n,element) .assign(pos_beg,pos_end) 旧的全部清理新的插入(pos_beg和pos_end是其他 列的位置)
调整:.resize(n,element=0) 把大小调整为n 添加的个数的内容是element首尾:.front(), .back() 可以修改首尾元素的值
增删:.push_back(element) .pop_back() 只删除,返回void
03sequence.cpp
#include <deque>
#include <iostream>
using namespace std;
#include "print.h"
#include <string>
int main()
{
deque<string> ds;
// deque< vector<int> >;
ds.push_back("曾文武");
ds.push_back("赵旭泽");
ds.push_back("薛小娟");
ds.push_back("高上");
print(ds.begin(),ds.end(),',');
ds.insert(++++ds.begin(),2,"芙蓉");
print(ds.begin(),ds.end(),',');
string s[3]={"张彦春","张永香","刘克磊"};
ds.insert(----ds.end(),s,s+3);
print(ds.begin(),ds.end(),',');
ds.pop_back(); ds.pop_back();
print(ds.begin(),ds.end(),',');
cout << "front:" << ds.front() << ",back:" << ds.back() << endl;
ds.resize(12,"郭益如");
print(ds.begin(),ds.end(),',');
ds.assign(5,"康森林");
print(ds.begin(),ds.end(),',');
//ds.clear();
ds.front() = "孙冬冬";
ds.back() = "梁振杰";
print(ds.begin(),ds.end(),',');
}
print.h
<span style="font-size:18px;">#ifndef PRINT_H
#define PRINT_H 1
//输出一个指定区间中的所有数据(含头不含尾)
template<typename T>
void print(T b, T e, char c=' ')
{
while(b!=e)
cout << *b++ << c;
cout << endl;
}
#endif
</span>
个性:
1.vector个性:其实就是一个动态数组(数组实现) 当容量不够时重新分配的大小是原来的两倍
vector迭代器在插入删除之后可能会失效因为可能会重新分配内存,如果插入删除过再用迭代器需要重新去取得
当前容量:.capacity()
约定容量:.reserver(n)只要不超过这个容量就不用重新再分配,以免反复重新分配空间
下标[]: .operator[](i)不检查越界 .at(i)这个函数做越界检查,越界会抛出异常
04vector.cpp
#include <iostream>
using namespace std;
#include <vector>
#include "print.h"
#include <exception>
#include <typeinfo>
int main()
{
vector<double> vd, vv;
for(int i=0; i<9; i++){
vd.push_back(i+0.1);
cout << &*vd.begin() << ':';得到首个元素的地址 会发现有变化
cout << vd.size() << '/' << vd.capacity() << endl;
}
cout << "------------------" << endl;
vv.reserve(9);
for(int i=0; i<9; i++){
vv.push_back(i+0.5);
cout << vv.size() << '/' << vv.capacity() << endl;
}
vd[3] = 123.45;
vv.at(5) = 67.8;
for(int i=0; i<=vd.size(); i++)
cout << vd[i] << ' ';
cout << endl;
try{
for(int i=0; i<=vv.size(); i++)
cout << vv.at(i) << ' ';
cout << endl;
}catch(exception& e){
cout << "异常:" << e.what() << endl;
cout << "类型:" << typeid(e).name() << endl;
}
int m=3, n=5;
void print(const vector< vector<int> >& v);
vector< vector<int> > vvi(m, vector<int>(n) );//二维数组
print(vvi);
vvi.resize(m+3);
vvi[1].assign(9,1);
vvi[5].assign(4,5);
print(vvi);
}
void print(const vector< vector<int> >& v)
{
for(int i=0; i<v.size(); i++){
for(int j=0; j<v[i].size(); j++){
cout << v[i][j] << ' ';
}
cout << endl;
}
}
2.deque的个性:double-ended queue下标[]: .operator[](i) 不检查越界, .at(i)越界抛异常
增删: .push_front(element), .push_back() .pop_front() .pop_back()
适合从前面插入或删除数据
05deque.cpp
#include <iostream>
using namespace std;
#include <deque>
#include "print.h"
int main()
{
deque<char> dc;
dc.push_back(97);dc.push_back('c');
dc.push_front('s');dc.push_front('d');
dc.push_back('k');dc.push_front('$');
print(dc.begin(),dc.end());//该函数在前面类中有定义
dc[1] = 't';
for(int i=0; i<dc.size(); i++)
cout << dc[i] << ',';
cout << endl;
dc.pop_back();
dc.pop_front();
print(dc.begin(),dc.end());
}
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) 两组都排好序的归并后的结果才是排好序的
06list.cpp
#include <iostream>
using namespace std;
#include <list>
#include "print.h"
#include <cassert>
bool compare(int x, int y)
{
x%=3, y%=3;
return x<y;
}
int main()
{
int a[10]={3,8,8,8,5,5,1,8,8,7}, b[6]={9,3,5,2,7,6};
list<int> li(a,a+10), lili(b,b+6);
print(li.begin(), li.end());
li.unique();
print(li.begin(), li.end());
li.sort();
print(li.begin(), li.end());
li.unique();
print(li.begin(), li.end());
li.reverse();
print(li.begin(), li.end());
li.splice(li.begin(),lili);//转移之后lili为空
print(li.begin(), li.end());
assert(lili.empty());
li.remove(5);
print(li.begin(), li.end());
li.sort();li.unique();
print(li.begin(), li.end());
lili.push_back(0);lili.push_back(4);lili.push_back(7);
lili.push_back(5);lili.push_back(10);
lili.sort();
print(lili.begin(), lili.end());
li.merge(lili);
print(li.begin(), li.end());
lili.assign(b,b+6);
print(lili.begin(), lili.end());
lili.sort(greater<int>());
print(lili.begin(), lili.end());
lili.sort(compare);
print(lili.begin(), lili.end());
}
——————————————————————————————————————————— 关联式容器共性:都是用二叉查找树实现的,都自动根据关键字排序
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>
using namespace std;
#include "../stl1/print.h"
struct Person{
string name;
int age;
public:
Person(const char* n, int a):name(n),age(a){}
};
bool operator<(const Person& a, const Person& b)
{return a.age<b.age||a.age==b.age&&a.name<b.name;}
ostream& operator<<(ostream&o, const Person& x)
{return o<<x.name<<':'<<x.age;}
int main()
{
multiset<Person> mp;
mp.insert(Person("赵元培",26));
mp.insert(Person("郭益如",18));
mp.insert(Person("姚连斌",20));
mp.insert(Person("赵元培",26));
mp.insert(Person("赵元培",26));
mp.insert(Person("王臣彬",21));
mp.insert(Person("郭益如",18));
mp.insert(Person("姚连斌",20));
mp.insert(Person("张洪铭",22));
mp.insert(Person("赵元培",26));
mp.insert(Person("郭益如",18));
mp.insert(Person("王臣彬",21));
mp.insert(Person("郭益如",18));
mp.insert(Person("王臣彬",21));
mp.insert(Person("郭益如",18));
print(mp.begin(), mp.end());
multiset<Person>::iterator it=mp.find(Person("张洪铭",22));
if(it==mp.end()) cout << "没有找到张洪铭" << endl;
else cout << "发现目标:" << *it << endl;
it=mp.find(Person("芙蓉",22));
if(it==mp.end()) cout << "没有找到芙蓉" << endl;
else cout << "发现目标:" << *it << endl;
it = mp.find(Person("郭益如",18));
cout << mp.count(*it) << "个" << *it << endl;
it = mp.find(Person("赵元培",26));
cout << mp.count(*it) << "个" << *it << endl;
multiset<Person>::iterator ib, ie;
ib = mp.lower_bound(Person("王臣彬",21));
ie = mp.upper_bound(Person("王臣彬",21));
cout << "===================" << endl;
print(ib, ie);
cout << "===================" << endl;
pair<multiset<Person>::iterator,multiset<Person>::iterator>p=mp.equal_range(Person("姚连斌",20));
print(p.first,p.second);
typedef multiset<Person>::iterator Iter;
pair<Iter,Iter>q=mp.equal_range(Person("郭益如",18));
print(q.first,q.second);
cout << "===================" << endl;
mp.erase(Person("郭益如",18));
mp.erase(Person("赵元培",26));
print(mp.begin(), mp.end());
}
个性:
1.map的个性:
不允许key重复
强调元素是map(key,value)一对
支持以key为下标访问对应的value的引用,如果key不存在就新增一个元素以这个为key。
别的关联式容器不支持以Key为下标
如果存的是对应关系就用map,如果存的只是关心的数据不存在对应关系就用set,set把整个元素作为key来比较。
02map.cpp
#include <iostream>
using namespace std;
#include <map>
#include "print.h"
struct P{
string name;
int age;
public:
P(){}
P(const char* n, int a):name(n),age(a){}
};
ostream& operator<<(ostream&o, const P& x)
{return o<<x.name<<':'<<x.age;}
int main()
{
map<int,P> mis;
mis.insert(map<int,P>::value_type(8,P("王龙",20)));
mis.insert(pair<int,P>(5,P("钟玉龙",22)));
mis.insert(make_pair(4,P("李霖",21)));
mis[3] = P("何军军",20);
mis[6] = P("蒲嗣良",23);
mis.insert(make_pair(5,P("芙蓉",18)));
print(mis.begin(), mis.end());
mis[6] = P("蒲松龄",300);
print(mis.begin(), mis.end());
}
print.h
#ifndef PRINT_H
#define PRINT_H 1
//输出一个指定区间中的所有数据(含头不含尾)
template<typename T>
void print(T b, T e, char c=' ')
{
while(b!=e)
cout << *b++ << c;
if(c!='\n') cout << endl;
}
template<typename K, typename V>
ostream& operator<<(ostream& o, const pair<K,V>& p)
{
return o << p.first << ':' << p.second;
}
#endif
2.multimap的个性:允许重复key
元素是key/value对
不支持方括号下标
04multiset.cpp
#include <map>
#include <iostream>
using namespace std;
#include "print.h"
#include <string>
int main()
{
typedef multimap<string,double> MSD;
MSD m;
m.insert(MSD::value_type("王刚",100000));
m.insert(make_pair("何军军",120000));
m.insert(make_pair("杨勇",20000));
m.insert(make_pair("何军军",160000));
m.insert(make_pair("杨勇",3000));
m.insert(MSD::value_type("王刚",220000));
m.insert(MSD::value_type("王刚",150000));
m.insert(make_pair("何军军",130000));
m.insert(make_pair("杨勇",1000000));
m.insert(make_pair("杨勇",110000));
print(m.begin(), m.end());
MSD::iterator ib = m.begin(), ie;
MSD cnt;
while(ib!=m.end()){
string name = ib->first;
ie = m.upper_bound(name);
double sum = 0.0;
while(ib!=ie) sum += ib++->second;
cnt.insert(make_pair(name,sum*0.03));
}
print(cnt.begin(),cnt.end());
}
3.set的个性
元素就是key
不允许重复key 如果重复就会被抛弃
可以默认被排好序
05set.cpp
#include <set>
#include <iostream>
using namespace std;
#include <string>
#include "print.h"
#include <fstream>
int main()
{
set<string> ss;//set<char*> ss;
string s;//char s[100];
ifstream fin("maillist");
if(!fin){return 1;}
while(fin>>s) ss.insert(s);
print(ss.begin(), ss.end(), '\n');
}
4.multiset的个性
元素就是key
允许有重复的key
06mutiset.cpp
#include <set>
#include <iostream>
using namespace std;
#include "print.h"
#include <string>
#include <map>
int main()
{
multiset<string> ms;
string name;
cout << "请输入你选举的人的姓名(Ctrl+D表示结束):\n";
while(cin>>name){//Ctrl+D表示输入结束
ms.insert(name);
}
print(ms.begin(), ms.end());
multiset<string>::iterator ib=ms.begin(), ie;
multimap<int,string> mis;
while(ib!=ms.end()){
mis.insert(make_pair(ms.count(*ib),*ib));
ib = ms.upper_bound(*ib);
}
print(mis.begin(),mis.end(),'\n');
}
————————————————————————————————————————————
迭代器:是一种检查容器内元素并遍历元素的数据类型
标准库为每种容器定义了一种迭代器类型,而且只有少数的容器比如vecotr deque支持下标操作
所以,一般容器都能使用迭代器来检查、遍历容器,有的还可以使用下标来实现
特殊容器:stack queue priority_queue
相同: .push(element) .pop() .empty() 都不提供迭代器
不同: 栈: .top()
队列 .front() .back()
优先队列 .top() 入的时候不讲究顺序,出的时候通过堆调整来实现最大的先出
07special.cpp
#include <queue>
#include <iostream>
using namespace std;
int main()
{
priority_queue<int> pq;
pq.push(50);pq.push(80);pq.push(20);pq.push(70);
pq.push(60);pq.push(30);
while(!pq.empty()){
cout << pq.top() << endl;
pq.pop();//最大的先出
}
}
priorty_queue使用堆调整:只保证最大的在前面 不保证别的