一、适配器分类
二、容器适配器
三、迭代器适配器
四、算法适配器
适配器是一种设计模式。
一、适配器分类
容器适配器:
stack 默认基于deque容器实现
queue 默认基于deque容器实现
priority_queue 默认基于vector容器实现
迭代器适配器
流迭代器
反向迭代器
插入迭代器
算法适配器(函数适配器)
绑定器
否定器
成员函数适配器
适配器并不是第一类容器,因为它们并没有提供与元素的保存形式有关的真正数据结构实现,并且适配器不支持迭代器。
适配器的优点是:能够使程序员选择一种合适的底层数据结构。
这三个适配器类都提供了成员函数push和pop,能够在每个适配器数据结构中正确地插入和删除元素。
二、容器适配器
没有full的方法,是因为可以无限放数据。
stack queue priority_queue
front 0 1 0 //返回队列中的第一个元素
top 1 0 1
empty 1 1 1
size 1 1 1
push 1 1 1
pop 1 1 1
emplace 1 1 1
swap 1 1 1
queue的使用
先进先出
#include <iostream>
#include <queue>
using std::cout;
using std::endl;
using std::queue;
int main(void){
queue<int> queInt;
for(int idx = 0; idx < 10; ++idx){
queInt.push(idx); //元素入队
cout << queInt.back() << "已经入队" << endl;
}
cout << queInt.size() << "个元素已经入队" << endl; //当前队列中有多少元素
while(!queInt.empty()){ //不为空
cout << queInt.front() << "出队" << endl; //返回队列中的第一个元素
queInt.pop(); //出队
}
cout << queInt.size() << endl;
return 0;
}
priority_queue的使用
优先级队列。
satck和queue不会根据优先级排序。优先级队列会排序。
默认情况下采用"<"进行排序。采用堆排序进行调整。堆顶元素优先级最高。所以priority_queue底层采用vector实现,因为二叉树容易使用数组实现。
例1:默认情况下使用"<"进行排序。
#include <iostream>
#include <queue>
#include <utility>
#include <vector>
using std::cout;
using std::endl;
using std::priority_queue;
using std::pair;
using std::vector;
int main(void){
int arr[10] = {0, 1, 3, 2, 5, 6, 9, 8, 7, 4};
priority_queue<int> pqueInt; //建立优先级队列
for(int idx = 0; idx != 10; ++idx){
pqueInt.push(arr[idx]);
//入队。入队的时候,就会比较,然后按照优先级进行插入。
cout << pqueInt.top() << "是优先级别最高的" << endl;
//打印出当前优先级最高的元素。优先级队列采用堆排序进行元素的调
整。默认情况下,比较函数是"<"符号。堆顶的元素要与新进来的元素
比较,如果为true(堆顶<新元素),则将新元素放到堆顶,然后调整堆。
如果为false,则放到最后。如1进来时,0<1,满足条件,则调整堆,1成为堆
顶。所以采用"<",数字越大优先级越高。
}
while(!pqueInt.empty()){
cout << pqueInt.top() << "出队" << endl; //获取队首元素(优先级最高的元素)
pqueInt.pop(); //出队:9 8 7 6 5 4 3 2 1 0
}
return 0;
}
例2:自定义类型,重载比较函数
#include <iostream>
#include <queue>
#include <utility>
#include <vector>
using std::cout;
using std::endl;
using std::priority_queue;
using std::pair;
using std::vector;
struct MyCompare{
bool operator()(const pair<int, bool> & lhs,const pair<int, bool> & rhs){
//定义一个类,重载函数调用运算符
return lhs.first > rhs.first;
}
};
int main(void){
priority_queue<
pair<int, bool>,vector<
pair<int, bool> >,MyCompare> quePair;
//创建优先级队列,存储的是pair.
quePair.push(std::make_pair(5, true));
//make_pair的返回值是pair。将5和true拼成一个pair,并返回
quePair.push(std::make_pair(3, false));
quePair.push(std::make_pair(7, true));
while(!quePair.empty()){
const pair<int, bool> & elem = quePair.top();
//elem是pair类型。pop的返回值是const的引用。
cout << elem.first << "-->" << elem.second << endl;
quePair.pop();
//3-->0 5-->1 7-->1
}
cout << endl;
return 0;
}
三、迭代器适配器
反向迭代器的使用
反向迭代器的开始位置在最后面,最后位置在最前面。
例:
#include <iostream>
#include <vector>
#include <iterator>
using std::cout;
using std::endl;
using std::vector;
using std::ostream_iterator;
int main(void){
vector<int> vecInt = {1, 2, 3, 4, 5};
ostream_iterator<int> osi(cout, " ");
//定义输出流迭代器
vector<int>::reverse_iterator rit = vecInt.rbegin();
//定义反向迭代器。
copy(rit, vecInt.rend(), osi);
//5 4 3 2 1 。
copy算法,将rit到vecInt.end()的数据放到osi
开始的容器中。
cout << endl;
return 0;
}
插入迭代器的使用
插入迭代器分为:头插法迭代器、尾插法迭代器、中间插入迭代器。
例:
#include <iostream>
#include <iterator>
#include <vector>
#include <list>
using std::cout;
using std::endl;
using std::vector;
using std::list;
template <typename T>
void printElements(T c){
typename T::iterator it;
for(it = c.begin(); it != c.end(); ++it){
cout << *it << " ";
}
cout << endl;
}
int main(){
vector<int> vecSrc = {1, 2, 3};
list<int> listDest;
copy(vecSrc.begin(), vecSrc.end(),std::back_insert_iterator<
list<int> >(
listDest));
//尾插法
printElements(listDest);
//1 2 3
copy(vecSrc.begin(), vecSrc.end(),std::front_insert_iterator<
list<int> >(
listDest));
//头插法
printElements(listDest);
// 3 2 1 1 2 3
copy(vecSrc.begin(), vecSrc.end(),std::insert_iterator<
list<int> >(
listDest,
++listDest.begin()));
//指定一个具体的位置。在第二个位置
printElements(listDest);
//3 1 2 3 2 1 1 2 3
return 0;
}
四、函数适配器
绑定器
band1st //已过时
band2nd //已过时
band //上面两个在c++11已经过时。由band代替。
std::band的返回值就是一个函数对象。
绑定的参数的个数不受限制;对于不事先绑定的参数,需要传std::placeholders进去,从_1开始,依次递增
例1:对自由函数进行绑定
#include <iostream>
#include <functional>
//band函数的头文件
using std::cout;
using std::endl;
int func(int x, int y){
return x + y;
}
int main(void){
using namespace std::placeholders;
//这样下面就不用写:std::placeholders::_1了。
auto f = std::bind(func, 10);
//错误。要写上占位符。
cout << f(20) << endl;
auto f1 = std::bind(func, 10, _1);
//func表示绑定到函数func。_1是占位符。占位符有两层含义。第一层含义是,本身
的位置表示在函数中形参的位置:这里_1在(func,10,_1)中是第2个参数,所以占着int
func(int x,int y); 的第二个参数的位置。而10就会传给x。第二层含义是,_1表示第一
个实参,所以下面f1(20)的20会传给_1.综上,当调用f1(20)时,会执行func(10,20)函数。
cout << f1(20) << endl;
//f1是一个函数对象。
return 0;
}
例2:对成员函数也可以绑定
#include <iostream>
#include <functional>
using std::cout;
using std::endl;
int func(int x, int y){
return x + y;
}
struct A{
A(){
cout << "A()" << endl;
}
A(const A & rhs){
//拷贝构造函数
cout << "A(const A&)" << endl;
}
int func(int x, int y){
cout << "A::func(int,int)" << endl;
cout << " x = " << x << endl;
cout << " y = " << y << endl;
return x + y;
}
};
int main(void){
using namespace std::placeholders;
A a;
auto f2 = std::bind(&A::func, a, _2, _1);
//bind的形参的绑定以值传递的形式进行的。绑定到类的成员函数func,注意写法。
第二个参数把对象传过去。后面_1和_2才是两个参数。
//bind的形参的绑定以值传递的形式进行的。a会以值传递的形式绑定到func,所以要
先根据a,执行拷贝构造函数,创建一个对象。所以这里可以使用&a,这样就不会再创
建
新的对象了。
cout << f2(1, 2) << endl;
//会执行成员函数。func(2,1) 。形参的第一个位置是第二个实参。形参的第二个位置是
第一个实参。
return 0;
}
例3:
#include <iostream>
#include <functional>
using std::cout;
using std::endl;
void f(int n1, int n2, int n3, const int & n4, int n5){
cout << "(" << n1<< "," << n2<< "," << n3<< "," << n4<< "," << n5<< ")" << endl;
}
int main(void){
using namespace std::placeholders;
int n = 7;
auto f1 = std::bind(f, _2, _1, 42, std::cref(n), n);
//绑定函数f。第一个形参是第二个实参,第二个形参是第一个实参。第三个形参是
42,第四个形参是n的引用,cref表示const reference。第五个参数将n传过去。
n = 10;
f1(1, 2, 1001, 1002, 1003);
//调用f1之后相当于执行f( 2, 1, 42, 10, 7),第二个实参传个第一个形参,为2;第1个实参
传个第二个形参,为1;第三个形参传42,第四个形参是n的引用,n变成了10,所以是10.
第五个参数绑定的是当时的n的值7.
//实参调用时,可以传递多余的参数,但是无效。这里的1001,1002,1003都没用。
return 0;
}
例4:绑定数据成员的值
#include <iostream>
#include <functional>
using std::cout;
using std::endl;
struct Foo{
int data = 10;
//直接初始化,这是C++11新特性。不建议这么写。
};
int main(void){
using namespace std::placeholders;
Foo foo;
foo.data = 12;
auto f3 = std::bind(
&Foo::data, _1);
//绑定数据成员。
cout << f3(foo) << endl;
//12。传的是对象。
return 0;
}
成员函数适配器
mem_fun() //已过时
mem_fun_ref() //已过时
mem_fn() //上面两个在c++11已经过时。