STL_容器適配器

那麼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. }  
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中的源碼:

  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.     };  
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實現的,它使用封裝的順序容器的操作來實現的自己的操作。相信裏面的大部分內容我們都能看懂個大概。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章