1. 程式人生 > >8、【C++ STL】容器介面卡(stack/queue/priority_queue)

8、【C++ STL】容器介面卡(stack/queue/priority_queue)

容器介面卡

    stack、queue、priority_queue 都不支援任一種迭代器,它們都是容器介面卡型別,stack是用vector/deque/list物件建立了一個先進後出容器;queue是用deque或list物件建立了一個先進先出容器;priority_queue是用vector/deque建立了一個排序佇列,內部用二叉堆實現。

1、stack

stack的原始碼如下:

// TEMPLATE CLASS stack
template < class _Ty,
         class _Container = deque<_Ty> >
class stack
{ // LIFO queue implemented with a container public: 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 } explicit stack(const _Container &_Cont) : c(_Cont) { // construct by copying specified container } 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); } protected: _Container c; // the underlying container };

    即有一個_Container 成員,預設是deque<_Ty> ,當然也可以傳遞vector, list 進去,只要支援push_back,pop_back 等介面。

stack示例

#include <iostream>
#include <vector>
#include <list>
#include <stack>

using namespace std;

int main(void)
{
    stack< int, list<int> > s;
    //add elements
    for(int i = 0; i < 5; i++)
    {
        s.push(i);
    }
    //print all elements
    while(!s.empty())
    {
        cout << s.top() << " ";
        s.pop();
    }
    cout << endl;

    return 0;
}
2、queue

queue的原始碼:

// TEMPLATE CLASS queue
template < class _Ty,
         class _Container = deque<_Ty> >
class queue
{
    // FIFO queue implemented with a container
public:
    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;

    queue()
        : c()
    {
        // construct with empty container
    }

    explicit queue(const _Container &_Cont)
        : c(_Cont)
    {
        // construct by copying specified container
    }

    bool empty() const
    {
        // test if queue is empty
        return (c.empty());
    }

    size_type size() const
    {
        // return length of queue
        return (c.size());
    }

    reference front()
    {
        // return first element of mutable queue
        return (c.front());
    }

    const_reference front() const
    {
        // return first element of nonmutable queue
        return (c.front());
    }

    reference back()
    {
        // return last element of mutable queue
        return (c.back());
    }

    const_reference back() const
    {
        // return last element of nonmutable queue
        return (c.back());
    }

    void push(const value_type &_Val)
    {
        // insert element at beginning
        c.push_back(_Val);
    }

    void pop()
    {
        // erase element at end
        c.pop_front();
    }

    const _Container &_Get_container() const
    {
        // get reference to container
        return (c);
    }

protected:
    _Container c;   // the underlying container
};

實現跟stack 是很類似的,只是queue不能用vector 實現,因為沒有pop_front 介面。

queue示例

#include <iostream>
#include <vector>
#include <list>
#include <stack>
#include <queue>

using namespace std;

int main(void)
{
    queue< int, list<int> > q;
    //add elements
    for(int i = 0; i < 5; i++)
    {
        q.push(i);
    }
    //print all elements
    while(!q.empty())
    {
        cout << q.front() << " ";
        q.pop();
    }
    cout << endl;

    return 0;
}
3、priority_queue

priority_queue的原始碼:

// TEMPLATE CLASS priority_queue
template < class _Ty,
         class _Container = vector<_Ty>,
         class _Pr = less<typename _Container::value_type> >
class priority_queue
{
    // priority queue implemented with a _Container
public:
    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;

    priority_queue()
        : c(), comp()
    {
        // construct with empty container, default comparator
    }

    explicit priority_queue(const _Pr &_Pred)
        : c(), comp(_Pred)
    {
        // construct with empty container, specified comparator
    }

    priority_queue(const _Pr &_Pred, const _Container &_Cont)
        : c(_Cont), comp(_Pred)
    {
        // construct by copying specified container, comparator
        make_heap(c.begin(), c.end(), comp);
    }

    template<class _Iter>
    priority_queue(_Iter _First, _Iter _Last)
        : c(_First, _Last), comp()
    {
        // construct by copying [_First, _Last), default comparator
        make_heap(c.begin(), c.end(), comp);
    }

    template<class _Iter>
    priority_queue(_Iter _First, _Iter _Last, const _Pr &_Pred)
        : c(_First, _Last), comp(_Pred)
    {
        // construct by copying [_First, _Last), specified comparator
        make_heap(c.begin(), c.end(), comp);
    }

    template<class _Iter>
    priority_queue(_Iter _First, _Iter _Last, const _Pr &_Pred,
                   const _Container &_Cont)
        : c(_Cont), comp(_Pred)
    {
        // construct by copying [_First, _Last), container, and comparator
        c.insert(c.end(), _First, _Last);
        make_heap(c.begin(), c.end(), comp);
    }

    bool empty() const
    {
        // test if queue is empty
        return (c.empty());
    }

    size_type size() const
    {
        // return length of queue
        return (c.size());
    }

    const_reference top() const
    {
        // return highest-priority element
        return (c.front());
    }

    reference top()
    {
        // return mutable highest-priority element (retained)
        return (c.front());
    }

    void push(const value_type &_Pred)
    {
        // insert value in priority order
        c.push_back(_Pred);
        push_heap(c.begin(), c.end(), comp);
    }

    void pop()
    {
        // erase highest-priority element
        pop_heap(c.begin(), c.end(), comp);
        c.pop_back();
    }

protected:
    _Container c;   // the underlying container
    _Pr comp;   // the comparator functor
};

    priority_queue 的實現稍微複雜一點,可以傳遞3個引數,而且有兩個成員,comp 即自定義比較邏輯,預設是less<value_type>,在建構函式中呼叫make_heap函式構造二叉堆,comp 主要是用於構造二叉堆時的判別,如果是less 則構造大堆,如果傳遞greater 則構造小堆.

    注意,priority_queue 不能用list 實現,因為list 只支援雙向迭代器,而不支援隨機迭代器。 priority_queue示例

#include <iostream>
#include <functional>
#include <vector>
#include <list>
#include <stack>
#include <queue>

using namespace std;

int main(void)
{
    int a[] = {5, 1, 2, 4, 3};
    //creat priority_queue and initialize priority_queue
    //less<int>構造大堆
    //greater<int>構造小堆
    priority_queue < int, vector<int>, less<int> > q(a, a+5);

    //print all elements
    while(!q.empty())
    {
        cout << q.top() << " ";
        q.pop();
    }
    cout << endl;

    return 0;
}

    在priority_queue的原始碼中用到了make_heap函式,下面舉個例子說明make_heap 函式的用法:

#include <iostream>
#include <functional>
#include <algorithm>//sort()
#include <iterator>//ostream_iterator
#include <vector>
#include <list>
#include <stack>
#include <queue>

using namespace std;

int main(void)
{
    int a[] = {5, 1, 2, 4, 3};
    make_heap(a, a+5, less<int>());

    //copy函式會將a,a+5區間的內的值拷貝至ostream_iterator中
    //ostream_iterator< int >(cout, " ")是一個函式物件,其功能是依次列印ostream_iterator中的
    //值,並以空格分割
    copy(a, a+5, ostream_iterator< int >(cout, " "));
    cout << endl;

    sort(a, a+5);

    //copy函式會將a,a+5區間的內的值拷貝至ostream_iterator中
    copy(a, a+5, ostream_iterator< int >(cout, " "));
    cout << endl;

    return 0;
}

執行結果:

    5 4 2 1 3
    1 2 3 4 5

    make_heap() 將容器的元素構造成二叉堆,傳遞的是less,即構造的是大堆,把大堆層序遍歷的結果存入陣列,再呼叫sort() 進行排序,內部呼叫的實際演算法不一定,可以是堆排序、插入排序、選擇排序等等,跟蹤進去發現呼叫的是插入排序;當然也可以直接指定使用堆排序 sort_heap(呼叫者必須已經是堆了,也就是前面已經先呼叫了make_heap,而且大小堆型別得匹配),與make_heap 一樣,第三個引數傳遞的都是函式物件的用法。sort 和 sort_heap 預設都是從小到大排序,除非過載的版本傳遞了第三個引數,如下,第三個引數可以是函式指標,也可以是函式物件:

// order heap by repeatedly popping, using operator<
template<class _RanIt> inline
void sort_heap(_RanIt _First, _RanIt _Last);

// order heap by repeatedly popping, using _Pred
template < class _RanIt,
         class _Pr > inline
void sort_heap(_RanIt _First, _RanIt _Last, _Pr _Pred);