C++学习:STL-适配器

一、适配器分类
二、容器适配器
三、迭代器适配器
四、算法适配器

适配器是一种设计模式。

一、适配器分类 
容器适配器:
  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已经过时。






猜你喜欢

转载自blog.csdn.net/pengchengliu/article/details/80545939