STL源碼結構解析之Stack,Queue,Priority_Queue

這裏的STL源碼結構解析的版本均是G++ 4.4.4。該源代碼可以在gun中下載,如果有安裝linux,一個STL源碼存儲再/usr/include/c++/目錄下。

文章先對STL中的stack,queue,priority_queue的異同點進行解析,接着分別解析了stack,queue,priority_queue的源碼結構實現方式。

 

stack,queue,priority_queue的相同點

之所以把stack,queue,priority_queue三者放在一起,是因爲這三種容器再STL中均屬於特殊容器。他們都具有如下特徵:

  1. 它們均是爲滿足特定需求而建立的容器。stack是爲了滿足FILO,queue是爲了滿足FIFO,priority_queue則是爲了滿足優先級高的元素先出隊列。
  2. 它們均具有一組含義非常明確的函數接口,比如stack的top,pop, push分別表示獲取棧頂元素,出棧和入棧,queue的front,back, pop, push分別表示獲取隊列首元素,隊列尾元素,出隊列和入隊列。
  3. 它們均不是標準的STL容器,卻都是以標準STL容器爲基礎。stack和queue默認是在deque的基礎上封裝的,priority_queue默認是在vector的基礎上封裝出來的。stack和queue的基礎容器之所以選擇deque而不選擇vector等容器,是因爲deque在刪除元素的時候可以釋放空間,同時在重新申請空間的時候無需拷貝所有元素。
  4. 它們均對基礎容器有一定的要求,這個要求是由他們滿足的需求確定的。比如stack需要從棧頂進出元素和獲取棧頂元素,它的基礎容器則需要提供back(), push_back(), pop_back()的函數。同理queue的基礎容器需要能夠提供back(), push_back(), pop_front(), priority_queue的基礎容器需要提供back(), push_back(), pop_back()的函數。
  5. 你可以你的需要,通過參數傳遞修改它們的基礎容器。比如
    stack<intvector<int> > st

對於stack和queue還有一個共同點,他們均有重載比較運算符,也就是說你可以對二個stack或者二個queue進行字典許的比較和排序。

STL的stack源碼解析

stack的模板可以傳遞二個參數,第一個是元素類型,第二個是可選的容器類型。類裏面有成員變量容器_Sequence c。構造函數有二個,一個函數的參數是左引用的,另外一個函數的參數爲右引用的。

template<typename _Tptypename _Sequence = deque<_Tp> >
    
class stack 
{
protected:
     
_Sequence c;
private:
    
explicit
      
stack(const _Sequence__c)
      : 
c(__c) { }
 
      
explicit
      
stack(_Sequence&& __c = _Sequence())
      : 
c(std::move(__c)) { }
}

stack的特定需求的函數則調用的是c的對應函數,比如下面的代碼push函數調用的是c的push_back。

void push(const value_type__x)
  
{ c.push_back(__x)}
  
void pop()
  
{ c.pop_back()}

二個stack的字典序大小也只直接調用容器c的大小比較來實現的。

template<typename _Tptypename _Seq>
    
inline bool operator<(const stack<_Tp_Seq>& __xconst stack<_Tp_Seq>& __y)
    
{ return __x.c < __y.c}

STL的queue源碼解析

由於queue的源碼原理和實現方式均跟stack相同,這裏就省略了。有興趣的朋友可以自己翻閱源碼。

STL的priority_queue源碼解析

priority_queue與前面二者不同的是priority_queue不僅僅進行簡單的出入隊列操作,在這些操作過程,還包括了堆的排序來進行內容的排序。它要求存儲元素已經定義了嚴格的排序關係less,且不提供相等或者大小的比較操作符號。priority_queue屬於基於優先級排序的queue,需要注意的是priority_queue默認使用的是最大堆,front()是堆中的最大元素。而且priority_queue在插入和刪除元素的時候維護隊列的正確性,如果你通過其他方式來操作隊列元素或者改變它們的順序,priority_queue不會重新對隊列中的元素重新排序。

priority_queue的模板支持三個參數,第一個參數是存儲元素類型,第二個參數是基礎容器,默認爲vector,第三個參數是比較運算符_Compare,默認爲less。爲了維護堆的正確性,再構造函數中即對容器進行make_heap的建堆操作。同時你還可以通過傳遞迭代器的方式來構造 一個priority_queue。

template<typename _Tptypename _Sequence = vector<_Tp>,
       
typename _Compare  = less<typename _Sequence::value_type> >
    
class priority_queue
{
protected:
      
_Sequence c;
public:
     
explicit
      
priority_queue(const _Compare__x,
             
const _Sequence__s)
      : 
c(__s)comp(__x)
      
{ std::make_heap(c.begin()c.end()comp)}
 
      
template<typename _InputIterator>
        
priority_queue(_InputIterator __first_InputIterator __last,
               
const _Compare__x = _Compare(),
               
_Sequence&& __s = _Sequence())
    : 
c(std::move(__s))comp(__x)
        
{
      
__glibcxx_requires_valid_range(__first__last);
      
c.insert(c.end()__first__last);
      
std::make_heap(c.begin()c.end()comp);
    
}
}

一些priority_queue的特殊需求函數跟stack一樣也是之間調用容器c的對應函數,比如size()函數和top()函數。

/**  Returns the number of elements in the %queue.  */
      
size_type
      
size() const
      
{ return c.size()}
 
      
/**
       *  Returns a read-only (constant) reference to the data at the first
       *  element of the %queue.
       */

      
const_reference
      
top() const
      
{
    
__glibcxx_requires_nonempty();
    
return c.front();
      
}

priority_queue與queue和stack另外二個不同的地方在於push()和pop()函數。因爲它需要再push()和pop()操作的時候進行堆的隊列維護,即調用push_heap和pop_heap函數。

void
      
push(const value_type__x)
      
{
    
c.push_back(__x);
    
std::push_heap(c.begin()c.end()comp);
      
}
 
    
void
      
pop()
      
{
    
__glibcxx_requires_nonempty();
    
std::pop_heap(c.begin()c.end()comp);
    
c.pop_back();
      
}

到此完成STL中特殊容器stack, queue, priority_queue的源碼機制解釋。如需深入瞭解,請查閱源代碼和相應書籍。

參考書籍

G++源碼,版本4.4.4

Nicolai M.Josuttis, The C++ Standard library

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