您的位置:首页 > 编程语言 > C语言/C++

从零开始学C++之STL(十一):容器适配器(stack、 queue 、priority_queue)源码浅析与使用示例

2013-07-28 10:44 971 查看
一、容器适配器

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++编程规范
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: