现在的位置: 首页 > 综合 > 正文

容器适配器的理解(转)

2017年12月20日 ⁄ 综合 ⁄ 共 4687字 ⁄ 字号 评论关闭

原文链接

首先,我们要明白适配器是干什么的?其实就是一个接口转换装置,是得我们能用特定的方法去操作一些我们本来无法操作的东西。举一个例子,比如你的一个设备支持串口线,而你的电脑支持的是usb口,这时候,我们没有必要重新买一个支持usb的设备,只需要一根串口转usb口的小玩意,让你的设备能够连接到usb插口上,而它就是适配器。
那么C++中的容器适配器是干什么的呢?可以做一个类比,我们已有的容器(比如vector、list、deque)就是设备,这个设备支持的操作很多,比如插入,删除,迭代器访问等等。而我们希望这个容器表现出来的是栈的样子:先进后出,入栈出栈等等,此时,我们没有必要重新动手写一个新的数据结构,而是把原来的容器重新封装一下,改变它的接口,就能把它当做栈使用了。
言归正传,理解了什么是适配器以后,其实问题就很简单的。C++中定义了3种容器适配器,它们让容器提供的接口变成了我们常用的的3种数据结构:栈(先进后出)队列(先进先出)和优先级队列(按照优先级(“<”号)排序,而不是按照到来的顺序排序)。
至于具体是怎么变的,我们可以先了解一个大概:默认情况下,栈和队列都是基于deque实现的,而优先级队列则是基于vector实现的。当然,我们也可以指定自己的实现方式。但是由于数据结构的关系,我们也不能胡乱指定。栈的特点是后进先出,所以它关联的基本容器可以是任意一种顺序容器,因为这些容器类型结构都可以提供栈的操作有求,它们都提供了push_back、pop_back和back操作。 队列queue的特点是先进先出,适配器要求其关联的基础容器必须提供pop_front操作,因此其不能建立在vector容器上;对于优先级队列,由于它要求支持随机访问的功能,所以可以建立在vector或者deque上,不能建立在list上。

让我们看看这三种关联容器提供的接口:
栈支持的操作有:
1.empty()  堆栈为空则返回真 
2.pop()  移除栈顶元素 
3.push()  在栈顶增加元素 
4.size()  返回栈中元素数目 
5.top()  返回栈顶元素 
队列支持的操作有:
1.back()  返回一个引用,指向最后一个元素 
2.empty()  如果队列空则返回真 
3.front()  返回第一个元素 
4.pop()  删除第一个元素 
5.push()  在末尾加入一个元素 
6.size()  返回队列中元素的个数 
优先级队列支持的操作有:
1.empty()  如果优先队列为空,则返回真 
2.pop()  删除第一个元素 
3.push()  加入一个元素 
4.size()  返回优先队列中拥有的元素的个数 
5.top()  返回优先队列中有最高优先级的元素

举个例子:

  1. int main()  
  2. {  
  3.     const stack<int>::size_type stk_size = 10;  
  4.     //创建一个空栈  
  5.     stack<int> intStack;  
  6.     //改变栈的实现方式为vector  
  7.     //stack<int,vector<int> > intStack;  
  8.     int ix = 0;  
  9.   
  10.     while(intStack.size() != stk_size)  
  11.         intStack.push(ix++);  
  12.   
  13.     int error_cnt = 0;  
  14.     while(intStack.empty() == false)  
  15.     {  
  16.         //top操作返回栈顶元素,但并不删除  
  17.         int value = intStack.top();  
  18.         if(value != --ix)  
  19.         {  
  20.             cout<<"opps! expected "<<ix<<" received "<<value<<endl;  
  21.             ++error_cnt;  
  22.   
  23.         }  
  24.         //删除栈顶元素  
  25.         intStack.pop();  
  26.     }  
  27.   
  28.     cout<<"our program ran with "<<error_cnt<<" errors! "<<endl;  
  29.     return 0;  
  30. }  


 

最后我们可以窥探一下stl中的源码:

  1. template<class _Ty,  
  2.     class _Container = deque<_Ty> >  
  3.     class stack  
  4.     {   // LIFO queue implemented with a container  
  5. public:  
  6.     typedef stack<_Ty, _Container> _Myt;  
  7.     typedef _Container container_type;  
  8.     typedef typename _Container::value_type value_type;  
  9.     typedef typename _Container::size_type size_type;  
  10.     typedef typename _Container::reference reference;  
  11.     typedef typename _Container::const_reference const_reference;  
  12.   
  13.     stack()  
  14.         : c()  
  15.         {   // construct with empty container  
  16.         }  
  17.   
  18.     stack(const _Myt& _Right)  
  19.         : c(_Right.c)  
  20.         {   // construct by copying _Right  
  21.         }  
  22.   
  23.     explicit stack(const _Container& _Cont)  
  24.         : c(_Cont)  
  25.         {   // construct by copying specified container  
  26.         }  
  27.   
  28.     _Myt& operator=(const _Myt& _Right)  
  29.         {   // assign by copying _Right  
  30.         c = _Right.c;  
  31.         return (*this);  
  32.         }  
  33.   
  34.     stack(_Myt&& _Right)  
  35.         : c(_STD move(_Right.c))  
  36.         {   // construct by moving _Right  
  37.         }  
  38.   
  39.     explicit stack(_Container&& _Cont)  
  40.         : c(_STD move(_Cont))  
  41.         {   // construct by copying specified container  
  42.         }  
  43.   
  44.     _Myt& operator=(_Myt&& _Right)  
  45.         {   // assign by moving _Right  
  46.         c = _STD move(_Right.c);  
  47.         return (*this);  
  48.         }  
  49.   
  50.     void push(value_type&& _Val)  
  51.         {   // insert element at beginning  
  52.         c.push_back(_STD move(_Val));  
  53.         }  
  54.   
  55.     template<class _Valty>  
  56.         void emplace(_Valty&& _Val)  
  57.         {   // insert element at beginning  
  58.         c.emplace_back(_STD forward<_Valty>(_Val));  
  59.         }  
  60.   
  61.     void swap(_Myt&& _Right)  
  62.         {   // exchange contents with movable _Right  
  63.         c.swap(_STD move(_Right.c));  
  64.         }  
  65.   
  66.     bool empty() const  
  67.         {   // test if stack is empty  
  68.         return (c.empty());  
  69.         }  
  70.   
  71.     size_type size() const  
  72.         {   // test length of stack  
  73.         return (c.size());  
  74.         }  
  75.   
  76.     reference top()  
  77.         {   // return last element of mutable stack  
  78.         return (c.back());  
  79.         }  
  80.   
  81.     const_reference top() const  
  82.         {   // return last element of nonmutable stack  
  83.         return (c.back());  
  84.         }  
  85.   
  86.     void push(const value_type& _Val)  
  87.         {   // insert element at end  
  88.         c.push_back(_Val);  
  89.         }  
  90.   
  91.     void pop()  
  92.         {   // erase last element  
  93.         c.pop_back();  
  94.         }  
  95.   
  96.     const _Container& _Get_container() const  
  97.         {   // get reference to container  
  98.         return (c);  
  99.         }  
  100.   
  101.     void swap(_Myt& _Right)  
  102.         {   // exchange contents with _Right  
  103.         c.swap(_Right.c);  
  104.         }  
  105.   
  106. protected:  
  107.     _Container c;   // the underlying container  
  108.     };  


从中我们可以清楚的看到:栈在默认情况下,是基于deque实现的,它使用封装的顺序容器的操作来实现的自己的操作。相信里面的大部分内容我们都能看懂个大概。这里就不做过多解释了。

抱歉!评论已关闭.