言歸正傳,理解了什麼是適配器以後,其實問題就很簡單的。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() 返回優先隊列中有最高優先級的元素
舉個例子:
- int main()
- {
- const stack<int>::size_type stk_size = 10;
- //創建一個空棧
- stack<int> intStack;
- //改變棧的實現方式爲vector
- //stack<int,vector<int> > intStack;
- int ix = 0;
- while(intStack.size() != stk_size)
- intStack.push(ix++);
- int error_cnt = 0;
- while(intStack.empty() == false)
- {
- //top操作返回棧頂元素,但並不刪除
- int value = intStack.top();
- if(value != --ix)
- {
- cout<<"opps! expected "<<ix<<" received "<<value<<endl;
- ++error_cnt;
- }
- //刪除棧頂元素
- intStack.pop();
- }
- cout<<"our program ran with "<<error_cnt<<" errors! "<<endl;
- return 0;
- }
int main()
{
const stack<int>::size_type stk_size = 10;
//創建一個空棧
stack<int> intStack;
//改變棧的實現方式爲vector
//stack<int,vector<int> > intStack;
int ix = 0;
while(intStack.size() != stk_size)
intStack.push(ix++);
int error_cnt = 0;
while(intStack.empty() == false)
{
//top操作返回棧頂元素,但並不刪除
int value = intStack.top();
if(value != --ix)
{
cout<<"opps! expected "<<ix<<" received "<<value<<endl;
++error_cnt;
}
//刪除棧頂元素
intStack.pop();
}
cout<<"our program ran with "<<error_cnt<<" errors! "<<endl;
return 0;
}
最後我們可以窺探一下stl中的源碼:
- template<class _Ty,
- class _Container = deque<_Ty> >
- class stack
- { // LIFO queue implemented with a container
- public:
- typedef stack<_Ty, _Container> _Myt;
- typedef _Container container_type;
- typedef typename _Container::value_type value_type;
- typedef typename _Container::size_type size_type;
- typedef typename _Container::reference reference;
- typedef typename _Container::const_reference const_reference;
- stack()
- : c()
- { // construct with empty container
- }
- stack(const _Myt& _Right)
- : c(_Right.c)
- { // construct by copying _Right
- }
- explicit stack(const _Container& _Cont)
- : c(_Cont)
- { // construct by copying specified container
- }
- _Myt& operator=(const _Myt& _Right)
- { // assign by copying _Right
- c = _Right.c;
- return (*this);
- }
- stack(_Myt&& _Right)
- : c(_STD move(_Right.c))
- { // construct by moving _Right
- }
- explicit stack(_Container&& _Cont)
- : c(_STD move(_Cont))
- { // construct by copying specified container
- }
- _Myt& operator=(_Myt&& _Right)
- { // assign by moving _Right
- c = _STD move(_Right.c);
- return (*this);
- }
- void push(value_type&& _Val)
- { // insert element at beginning
- c.push_back(_STD move(_Val));
- }
- template<class _Valty>
- void emplace(_Valty&& _Val)
- { // insert element at beginning
- c.emplace_back(_STD forward<_Valty>(_Val));
- }
- void swap(_Myt&& _Right)
- { // exchange contents with movable _Right
- c.swap(_STD move(_Right.c));
- }
- bool empty() const
- { // test if stack is empty
- return (c.empty());
- }
- size_type size() const
- { // test length of stack
- return (c.size());
- }
- reference top()
- { // return last element of mutable stack
- return (c.back());
- }
- const_reference top() const
- { // return last element of nonmutable stack
- return (c.back());
- }
- void push(const value_type& _Val)
- { // insert element at end
- c.push_back(_Val);
- }
- void pop()
- { // erase last element
- c.pop_back();
- }
- const _Container& _Get_container() const
- { // get reference to container
- return (c);
- }
- void swap(_Myt& _Right)
- { // exchange contents with _Right
- c.swap(_Right.c);
- }
- protected:
- _Container c; // the underlying container
- };
template<class _Ty,
class _Container = deque<_Ty> >
class stack
{ // LIFO queue implemented with a container
public:
typedef stack<_Ty, _Container> _Myt;
typedef _Container container_type;
typedef typename _Container::value_type value_type;
typedef typename _Container::size_type size_type;
typedef typename _Container::reference reference;
typedef typename _Container::const_reference const_reference;
stack()
: c()
{ // construct with empty container
}
stack(const _Myt& _Right)
: c(_Right.c)
{ // construct by copying _Right
}
explicit stack(const _Container& _Cont)
: c(_Cont)
{ // construct by copying specified container
}
_Myt& operator=(const _Myt& _Right)
{ // assign by copying _Right
c = _Right.c;
return (*this);
}
stack(_Myt&& _Right)
: c(_STD move(_Right.c))
{ // construct by moving _Right
}
explicit stack(_Container&& _Cont)
: c(_STD move(_Cont))
{ // construct by copying specified container
}
_Myt& operator=(_Myt&& _Right)
{ // assign by moving _Right
c = _STD move(_Right.c);
return (*this);
}
void push(value_type&& _Val)
{ // insert element at beginning
c.push_back(_STD move(_Val));
}
template<class _Valty>
void emplace(_Valty&& _Val)
{ // insert element at beginning
c.emplace_back(_STD forward<_Valty>(_Val));
}
void swap(_Myt&& _Right)
{ // exchange contents with movable _Right
c.swap(_STD move(_Right.c));
}
bool empty() const
{ // test if stack is empty
return (c.empty());
}
size_type size() const
{ // test length of stack
return (c.size());
}
reference top()
{ // return last element of mutable stack
return (c.back());
}
const_reference top() const
{ // return last element of nonmutable stack
return (c.back());
}
void push(const value_type& _Val)
{ // insert element at end
c.push_back(_Val);
}
void pop()
{ // erase last element
c.pop_back();
}
const _Container& _Get_container() const
{ // get reference to container
return (c);
}
void swap(_Myt& _Right)
{ // exchange contents with _Right
c.swap(_Right.c);
}
protected:
_Container c; // the underlying container
};
從中我們可以清楚的看到:棧在默認情況下,是基於deque實現的,它使用封裝的順序容器的操作來實現的自己的操作。相信裏面的大部分內容我們都能看懂個大概。