一、适配器分类
二、容器适配器
三、迭代器适配器
四、算法适配器
适配器是一种设计模式。
一、适配器分类
容器适配器:
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已经过时。