当前位置:   article > 正文

容器适配器stack,queue和priority_queue

容器适配器

目录

一.什么是容器适配器

二.stack栈

2.1 stack的介绍

 2.2 stack的使用

 2.3 stack的模拟实现

三.queue队列

3.1 queue介绍

 3.2 queue的使用

 3.3queue的模拟实现

四.priority_queue优先队列

4.1priority_queue介绍

4.2 priority_queue使用

4.3优先队列的模拟实现


一.什么是容器适配器

        容器适配器是一个封装了序列容器的一个类模板,它在一般的序列容器的基础上提供了一些不同的功能。之所以称为容器适配器,是因为它是适配容器来提供其它不一样的功能。通过对应的容器和成员函数来实现我们需要的功能。

        下面介绍了三个容器适配器:statk<T>,queue<T>,priority_queue<T>。

        注意:容器适配器都不存在迭代器。

二.stack栈

2.1 stack的介绍

  1. stack是一种后进先出特点的容器适配器。其删除和插入操作只能在容器的一端进行。即只能在栈顶插入和弹出。
  2. stack的底层容器可以是任何标准的容器类模板或者其它特定的类容器(你设计的容器),但是这些容器必须支持以下操作:empty(判空),back(获取尾部元素),push_back(尾插),pop_back(尾删),size(获取元素大小)。
  3. vector,list,deque皆可作为stack的底层容器,默认情况下,如果没有为stack指定容器,默认使用deque作为默认容器。

 2.2 stack的使用

函数名称功能
stack()构造一个空栈
empty()判断栈是否为空,空返回true,非空返回false
size()返回栈元素个数
top()返回栈顶元素的引用
push()在栈顶插入元素
pop()将stack栈顶元素弹出

 使用stack需要包含头文件#include<stack>,stack不存在迭代器。

 2.3 stack的模拟实现

  1. #include<iostream>
  2. #include<deque>
  3. #include<vector>
  4. #include<list>
  5. using namespace std;
  6. namespace my{
  7. template<class T,class Container=deque<T>>
  8. class stack{
  9. public:
  10. bool empty(){
  11. return _con.empty();
  12. }
  13. size_t size(){
  14. return _con.size();
  15. }
  16. T& top(){
  17. return _con.back();
  18. }
  19. const T& top()const{
  20. return back();
  21. }
  22. void push(const T& val){
  23. _con.push_back(val);
  24. }
  25. void pop(){
  26. _con.pop_back();
  27. }
  28. private:
  29. Container _con;
  30. };
  31. void test_stack(){
  32. stack<int> s;
  33. s.push(1);
  34. s.push(2);
  35. s.push(3);
  36. s.push(4);
  37. while (!s.empty())
  38. {
  39. cout << s.top() << " ";
  40. s.pop();
  41. }
  42. cout << endl;
  43. }
  44. void test_stack1(){
  45. stack<int,list<int>> s;
  46. s.push(1);
  47. s.push(2);
  48. s.push(3);
  49. s.push(4);
  50. while (!s.empty())
  51. {
  52. cout << s.top() << " ";
  53. s.pop();
  54. }
  55. cout << endl;
  56. }
  57. }

三.queue队列

3.1 queue介绍

        

  1.  队列是一种先进先出容器适配器,其中从容器的一段插入,另一端提取元素。在队尾插入,在对头弹出元素。
  2. 底层容器是标准容器类模板之一,也可以只用你专门设计的容器类,该容器必须支持empty(判空),front(获取队头元素的引用),back(获取队尾元素引用),push_back(尾插),pop_front(头删),size(获取元素大小)。
  3. vector,list和deque满足这些要求。默认情况下,没显示给出queue指定容器,默认使用deque。

 3.2 queue的使用

函数声明功能介绍
queue()构造空队列
size()返回队列中的元素个数
empty()判断队列是否为空
back()返回队尾元素引用
front()返回队头元素引用
push()在对尾插入元素
pop()将队头元素弹出

 使用queue需要包含头文件#include<queue>,queue容器适配器没有迭代器

 3.3queue的模拟实现

因为queue存在头删和尾插,因此使用vector容器来封装效率太低,头删需要挪动数据,并且vector并没有提供pop_front(),因为效率太低。

  1. #pragma once
  2. #include<iostream>
  3. #include<deque>
  4. #include<vector>
  5. #include<list>
  6. using namespace std;
  7. namespace my{
  8. template<class T, class Container = deque<T>>
  9. class queue{
  10. public:
  11. //会调用容器构造函数
  12. queue(){};
  13. //注意有隐含this指针
  14. size_t size()const{
  15. return _con.size();
  16. }
  17. bool empty()const{
  18. return _con.empty();
  19. }
  20. T& back(){
  21. return _con.back();
  22. }
  23. T& front(){
  24. return _con.front();
  25. }
  26. const T& back()const{
  27. return _con.back();
  28. }
  29. const T& front()const{
  30. return _con.front();
  31. }
  32. void push(const T& val){
  33. _con.push_back(val);
  34. }
  35. void pop()
  36. {
  37. _con.pop_front();
  38. }
  39. private:
  40. Container _con;
  41. };
  42. void test_queue1(){
  43. queue<int> q;
  44. q.push(1);
  45. q.push(2);
  46. q.push(3);
  47. q.push(4);
  48. cout << q.size() << endl;
  49. cout << q.back() << endl;
  50. cout << q.front() << endl;
  51. while (!q.empty()){
  52. cout << q.front() << " ";
  53. q.pop();
  54. }
  55. cout << endl;
  56. }
  57. }

四.priority_queue优先队列

4.1priority_queue介绍

  1.  优先队列是容器适配器,根据若排序标准,它的第一个元素总是它所包含的元素中优先级最高的。(或许值是最大的,或许是最小的),就像数据结构里的
  2. 优先队列默认形成大堆
  3. 优先队列的元素从顶部弹出,顶部是优先级最高的。
  4. 底层容器可以是任何容器的类模板,也可以是其他特定设计的容器类(自己设计的),容器支持的功能:随机访问operator[],empty,size,front,push_back,pop_front。
  5. 标准容器vector和deque都可以满足这些需求,没显示定义容器模板时,优先队列默认使用vector。
  6. 优先队列使用仿函数来控制生成大根堆还是生成小根堆。

简单介绍一下仿函数:

        仿函数(Functor)又称为函数对象(Function Object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载 operator() 运算符。因为调用仿函数,实际上就是通过类对象调用重载后的 operator() 运算符。仿函数是一个类,只是使用起来像函数。等下模拟实现时就知道了。

4.2 priority_queue使用

优先队列默认使用vector作为存储数据的容器,在容器的基础上使用堆算法,将vector中的元素调整成一个堆结构。

注意:优先队列就是一个堆,在使用堆的地方都可以使用优先队列。默认生成大根堆,头文件也是#include<queue>

函数功能
priority_queue()建立一个空优先队列
priority_queue(first,last)将迭代器first到last之间的元素建堆
top返回优先级队列中优先级最高元素,即堆顶元素
size返回优先队列里的元素个数
empty判断优先队列是否为空
push往优先队列中插入元素
pop删除优先级队列中优先级最高元素,即堆顶元素

 注意:如果在priority_queue中放自定义类型的数据,即在存储数据的容器中放自定义类型数据需要将操作符<和>重载,因为要进行调整称堆。

4.3优先队列的模拟实现

        回顾一下堆的插入与删除操作。

        堆的插入:在堆尾插入数据,再向上调整成堆。

        堆的删除:将堆顶元素和对尾元素交换,再向下调整成堆。

不带仿函数:

        调整函数:

  1. #pragma once
  2. #include<iostream>
  3. #include<deque>
  4. #include<vector>
  5. #include<list>
  6. using namespace std;
  7. namespace my{
  8. template<class T,class Container = vector<T>>
  9. class priority_queue{
  10. public:
  11. priority_queue(){};
  12. template<class inputiterator>
  13. priority_queue(inputiterator first, inputiterator last){
  14. while (first != last){
  15. push(*first);
  16. first++;
  17. }
  18. }
  19. bool empty(){
  20. return _con.empty();
  21. }
  22. size_t size(){
  23. return _con.size();
  24. }
  25. T& top(){
  26. return _con.front();
  27. }
  28. const T& top()const{
  29. return _con.front();
  30. }
  31. void push(const T& val){
  32. _con.push_back(val);
  33. Adjustup(_con.size() - 1);
  34. }
  35. void pop(){
  36. swap(_con[0], _con[_con.size() - 1]);
  37. //少一个元素是size减减,交换后,直接删除最后一个元素
  38. _con.pop_back();
  39. Adjustdown(0);
  40. }
  41. private:
  42. void Adjustup(int child){
  43. int parent = (child - 1) / 2;
  44. while (child > 0){
  45. if (_con[child] > _con[parent]){
  46. swap(_con[child], _con[parent]);
  47. child = parent;
  48. parent = (child - 1) / 2;
  49. }
  50. else{
  51. break;
  52. }
  53. }
  54. }
  55. void Adjustdown(int parent){
  56. int child = parent * 2 + 1;
  57. //不能减1,如果没有元素size()为0,类型size_t,减1就是最大的数(正数),会进入循环
  58. while ((size_t)child < _con. size() ){
  59. if (child + 1 < _con.size() && _con[child + 1] > _con[child]){
  60. child++;
  61. }
  62. if (_con[child]>_con[parent]){
  63. swap(_con[child], _con[parent]);
  64. parent = child;
  65. child = parent * 2 + 1;
  66. }
  67. else{
  68. break;
  69. }
  70. }
  71. }
  72. Container _con;
  73. };
  74. void test_priority_queue(){
  75. int array[] = { 8, 4, 6, 2, 10 };
  76. priority_queue<int> pq(array, array + sizeof(array) / sizeof(int));
  77. cout << pq.size() << endl;
  78. while (!pq.empty()){
  79. cout << pq.top() << " ";
  80. pq.pop();
  81. }
  82. cout << endl;
  83. }
  84. }

仿函数:优先队列通过仿函数来实现建立大根堆还是小根堆。

调整建立大根堆还是小根堆,只需要改变调整函数。父亲结点与孩子结点比较时的大于小于号。怎么通过仿函数来实现呢?

调整函数怎么修改:

  1. #pragma once
  2. #include<iostream>
  3. #include<deque>
  4. #include<vector>
  5. #include<list>
  6. using namespace std;
  7. namespace my{
  8. template<class T>
  9. struct less{
  10. bool operator()(const T& left,const T& right){
  11. return left < right;
  12. }
  13. };
  14. template<class T>
  15. struct greater{
  16. bool operator()(const T& left, const T& right){
  17. return left>right;
  18. }
  19. };
  20. template<class T,class Container = vector<T>,class Compare=less<T>>
  21. class priority_queue{
  22. public:
  23. priority_queue(){};
  24. template<class inputiterator>
  25. priority_queue(inputiterator first, inputiterator last){
  26. while (first != last){
  27. push(*first);
  28. first++;
  29. }
  30. }
  31. bool empty(){
  32. return _con.empty();
  33. }
  34. size_t size(){
  35. return _con.size();
  36. }
  37. T& top(){
  38. return _con.front();
  39. }
  40. const T& top()const{
  41. return _con.front();
  42. }
  43. void push(const T& val){
  44. _con.push_back(val);
  45. Adjustup(_con.size() - 1);
  46. }
  47. void pop(){
  48. swap(_con[0], _con[_con.size() - 1]);
  49. //少一个元素是size减减,交换后,直接删除最后一个元素
  50. _con.pop_back();
  51. Adjustdown(0);
  52. }
  53. private:
  54. void Adjustup(int child){
  55. int parent = (child - 1) / 2;
  56. Compare com;
  57. while (child){
  58. if (com(_con[parent],_con[child])){
  59. swap(_con[child], _con[parent]);
  60. child = parent;
  61. parent = (child - 1) / 2;
  62. }
  63. else{
  64. break;
  65. }
  66. }
  67. }
  68. void Adjustdown(int parent){
  69. int child = parent * 2 + 1;
  70. //定义一个对象
  71. Compare com;
  72. //不能减1,如果没有元素size()为0,类型size_t,减1就是最大的数(正数),会进入循环
  73. while ((size_t)child < _con. size() ){
  74. if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){
  75. child++;
  76. }
  77. if (com(_con[parent], _con[child])){
  78. swap(_con[child], _con[parent]);
  79. parent = child;
  80. child = parent * 2 + 1;
  81. }
  82. else{
  83. break;
  84. }
  85. }
  86. }
  87. Container _con;
  88. };
  89. void test_priority_queue(){
  90. int array[] = { 8, 4, 6, 2, 10 };
  91. priority_queue<int,vector<int>,greater<int>> pq(array, array + sizeof(array) / sizeof(int));
  92. cout << pq.size() << endl;
  93. while (!pq.empty()){
  94. cout << pq.top() << " ";
  95. pq.pop();
  96. }
  97. cout << endl;
  98. }
  99. }

        


 

        

        

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/197910?site
推荐阅读
相关标签
  

闽ICP备14008679号