• 容器适配器(stack、 queue 、priority_queue)源码浅析与使用示例


    一、容器适配器
    stack
    queue
    priority_queue

    stack、queue、priority_queue 都不支持任一种迭代器,它们都是容器适配器类型,stack是vector/deque/list对象创建了一个先进后出容器;queue是用deque或list对象创建了一个先进先出容器;priority_queue是用vector/deque创建了一个排序队列,内部用二叉堆实现。


    前面或多或少谈到过list/vector的实现,而没提到过deque的实现,可以用以下一句话概括,具体可以看看《stl源码剖析》:

    Storing contents in multiple smaller arrays, allocating additional arrays at the beginning or end as needed.
    Indexing is implemented by keeping a dynamic array containing pointers to each of the smaller arrays.



    (一)、stack

    首先来看示例代码:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    #include <iostream>
    #include <vector>
    #include <list>
    #include <stack>

    using namespace std;

    int main(void)
    {
        stack<int, list<int> > s;
        for (int i = 0; i < 5; i++)
        {
            s.push(i);
        }

        //for (size_t i=0; i<s.size(); i++)
        //{
        //  cout<<s.top()<<' ';   Error:size()一直在变化
        //  s.pop();
        //}

        while (!s.empty())
        {
            cout << s.top() << ' ';
            s.pop();
        }
        cout << endl;
        return 0;
    }

    再看stack 的源码:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
     
    // 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 很像。


    (二)、queue

    先来看示例代码:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    #include <iostream>
    #include <vector>
    #include <list>
    #include <stack>
    #include <queue>

    using namespace std;

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

        queue<int, list<int> > q;
        for (int i = 0; i < 5; i++)
        {
            q.push(i);
        }

        while (!q.empty())
        {
            cout << q.front() << ' ';
            q.pop();
        }

        cout << endl;

        return 0;
    }

    再来看queue 源码:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
     
    // 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 接口。


    (三)、priority_queue

    先来看示例代码:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    #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};
        priority_queue<int, vector<int>, greater<int> > q(a, a + 5);

        while (!q.empty())
        {
            cout << q.top() << ' ';
            q.pop();
        }

        cout << endl;

        return 0;
    }

    再来看priority_queue 的源码:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
     
    // 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 只支持双向迭代器,而不支持随机迭代器。

    下面举个例子说明make_heap 函数的用法:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    #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};
        make_heap(a, a + 5, less<int>());

        copy(a, a + 5, ostream_iterator<int>(cout, " "));
        cout << endl;

        sort(a, a + 5);
        //  sort_heap(a, a+5, less<int>());
        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 默认都是从小到大排序,除非重载的版本传递了第三个参数,如下,第三个参数可以是函数指针,也可以是函数对象:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
     
    // 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);

    传递greater 构造的是小堆,如下图所示:



    参考:

    C++ primer 第四版
    Effective C++ 3rd
    C++编程规范

  • 相关阅读:
    nohub和 2>&1 &
    postman
    ximd 破解版
    B树和B+树的插入、删除图文详解
    漫画叙述B+树和B-树,很值得看!
    数据库 操作的几个问题记录
    推送实现 应用未启动情况下的自定义声音播放
    collectionView reloadData时 点击问题
    强制横屏或者竖屏
    wkWebView 或者 webView 在客户端隐藏某些布局的方法
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8471474.html
Copyright © 2020-2023  润新知