stack 和 queue
文章目录
- 1. stack的使用
- 2. queue的使用
- 3. stack的模拟实现
- 4. queue的模拟实现
- 5. deque的简单介绍
- 6. priority_queue的使用
- 7. priority_queue的模拟实现
1. stack的使用
#include <iostream>
using namespace std;
#include <stack>void test_stack()
{stack<int> s;s.push(1);s.push(2);s.push(3);s.push(4);while (!s.empty()){cout << s.top() << " ";s.pop();}cout << endl;
}int main()
{test_stack();return 0;
}
最小栈
class MinStack {
public:MinStack() {}void push(int val) {_st.push(val);if (_minst.empty() || val <= _minst.top()){_minst.push(val);}}void pop() {if (_minst.top() == _st.top()){_minst.pop();}_st.pop();}int top() {return _st.top();}int getMin() {return _minst.top();}private:stack<int> _st;stack<int> _minst;
};
栈的压入、弹出序列
class Solution {
public:/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param pushV int整型vector * @param popV int整型vector * @return bool布尔型*/bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {size_t popi = 0;stack<int> s;for (auto e : pushV){s.push(e);// 栈顶数据跟出栈序列比较while (!s.empty() && s.top() == popV[popi]){++popi;s.pop();}}return s.empty();}
};
2. queue的使用
二叉树的层序遍历
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> vv;if (root == nullptr){return vv;}queue<TreeNode*> q;q.push(root);int levelSize = 1;while (!q.empty()){vector<int> v;// 控制一层一层出完while (levelSize--){TreeNode* front = q.front();q.pop();v.push_back(front->val);if (front->left){q.push(front->left);}if (front->right){q.push(front->right);}}vv.push_back(v);// 当前层出完了,下一层都在队列中levelSize = q.size();}return vv;}
};
3. stack的模拟实现
//Stack.h#include <vector>
#include <list>
#include <deque>namespace bit
{/*template<class T>class Stack{private:T* _a;int _top;int _capacity;};*/// 可维护性// 设计模式// 适配器模式 -- 封装转换// 迭代器模式 -- 封装统一访问方式(数据结构访问都可以用)template<class T, class Container = deque<T>>class stack{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}const T& top(){return _con.back();}bool empty(){return _con.empty();}size_t size(){_con.size();}private:Container _con;};
}
//Test.cpp#include <iostream>
using namespace std;#include "Stack.h"void test_stack()
{//bit::stack<int, vector<int>> s;//bit::stack<int, list<int>> s;bit::stack<int, deque<int>> s;//bit::stack<int> s;s.push(1);s.push(2);s.push(3);s.push(4);while (!s.empty()){cout << s.top() << " ";s.pop();}cout << endl;
}int main()
{test_stack();return 0;
}
C语言也可以模拟成员函数:
void PushBack(int x)
{printf("void PushBack(int x)\n");
}//C
typedef struct Vector
{void(*push_back)(int);int* _a;int _size;int _capacity;
}Vector;void Init(struct Vector* pv)
{pv->push_back = PushBack;//...
}int main()
{Vector v;Init(&v);v.push_back(1);v.push_back(2);return 0;
}
4. queue的模拟实现
//Queue.h#include <vector>
#include <list>
#include <deque>namespace bit
{// deque list// 不支持vectortemplate<class T, class Container = deque<T>>class queue{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();//这样就可以支持vector了,但是效率就很低了//_con.erase(_con.begin());}const T& back(){return _con.back();}const T& front(){return _con.front();}bool empty(){return _con.empty();}size_t size(){_con.size();}private:Container _con;};
}
//Test.cpp#include <iostream>
using namespace std;#include "Queue.h"void test_queue()
{bit::queue<int> q;//bit::queue<int, list<int>> q;// 不支持//bit::queue<int, vector<int>> q;q.push(1);q.push(2);q.push(3);q.push(4);while (!q.empty()){cout << q.front() << " ";q.pop();}cout << endl;
}int main()
{test_queue();return 0;
}
5. deque的简单介绍
deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。
deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图所示:
#include <iostream>
using namespace std;#include <vector>
#include <deque>void test_op1()
{srand(time(0));const int N = 1000000;deque<int> dq;vector<int> v;for (int i = 0; i < N; ++i){auto e = rand() + i;v.push_back(e);dq.push_back(e);}int begin1 = clock();sort(v.begin(), v.end());int end1 = clock();int begin2 = clock();sort(dq.begin(), dq.end());int end2 = clock();printf("vector:%d\n", end1 - begin1);printf("deque:%d\n", end2 - begin2);
}void test_op2()
{srand(time(0));const int N = 1000000;deque<int> dq1;deque<int> dq2;for (int i = 0; i < N; ++i){auto e = rand() + i;dq1.push_back(e);dq2.push_back(e);}int begin1 = clock();sort(dq1.begin(), dq1.end());int end1 = clock();int begin2 = clock();// 拷贝到vectorvector<int> v(dq2.begin(), dq2.end());sort(v.begin(), v.end());dq2.assign(v.begin(), v.end());int end2 = clock();printf("deque sort:%d\n", end1 - begin1);printf("deque copy vector sort, copy back deque:%d\n", end2 - begin2);
}int main()
{//test_op1();test_op2();return 0;
}
双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,因此deque的迭代器设计就比较复杂,如下图所示:
为什么选择deque作为stack和queue的底层默认容器:
stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如list。
但是STL中对stack和queue默认选择deque作为其底层容器,主要是因为:
- stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
- 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高。
结合了deque的优点,而完美的避开了其缺陷。
6. priority_queue的使用
#include <iostream>
using namespace std;#include <queue>// 默认是大堆
void test_priority_queue()
{//vector<int> v = { 3, 2, 7, 6, 0, 4, 1, 9, 8, 5 };///*priority_queue<int> q1;//for (auto& e : v)//{// q1.push(e);//}*///priority_queue<int> q1(v.begin(), v.end());int a[] = { 3, 2, 7, 6, 0, 4, 1, 9, 8, 5 };// 默认是大堆//priority_queue<int> q1(a, a + sizeof(a) / sizeof(int));// 小堆priority_queue<int, vector<int>, greater<int>> q1(a, a + sizeof(a) / sizeof(int));while (!q1.empty()){cout << q1.top() << " ";q1.pop();}cout << endl;
}int main()
{test_priority_queue();return 0;
}
7. priority_queue的模拟实现
//PriorityQueue.h#include <vector>namespace bit
{template<class T, class Container = vector<T>>class priority_queue{public:// 强制编译器生成priority_queue() = default;template<class InputIterator>priority_queue(InputIterator first, InputIterator last){while (first != last){_con.push_back(*first);++first;}// 建堆for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--){adjust_down(i);}}void adjust_up(int child){int parent = (child - 1) / 2;while (child > 0){if (_con[parent] < _con[child]){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){_con.push_back(x);adjust_up(_con.size() - 1);}void adjust_down(int parent){size_t child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && _con[child] < _con[child + 1]){++child;}if (_con[parent] < _con[child]){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down(0);}const T& top(){return _con[0];}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};
}
//Test.cpp#include <iostream>
using namespace std;#include "PriorityQueue.h"void test_priority_queue()
{int a[] = { 3, 2, 7, 6, 0, 4, 1, 9, 8, 5 };// 默认是大堆bit::priority_queue<int> q1(a, a + sizeof(a) / sizeof(int));while (!q1.empty()){cout << q1.top() << " ";q1.pop();}cout << endl;
}int main()
{test_priority_queue();return 0;
}
#include <iostream>
using namespace std;#include <string>// 仿函数/函数对象:重载了operator()的类,类的对象可以像函数一样使用
// operator()特点,参数个数和返回值根据需求确定,不固定,很灵活
class Func
{
public:void operator()(int n){while (n--){cout << "Func调用" << endl;}cout << endl;}
};template<class T>
class myless
{
public:bool operator()(const T& x, const T& y){return x < y;}
};int main()
{Func f1;f1(10);f1.operator()(10);myless<int> lessFunc1;cout << lessFunc1(1, 2) << endl;// lessFunc1.operator()(1, 2);myless<string> lessFunc2;cout << lessFunc2("1111", "22222") << endl;return 0;
}
//PriorityQueue.h#include <vector>namespace bit
{template<class T>class myless{public:bool operator()(const T& x, const T& y){return x < y;}};template<class T>class mygreater{public:bool operator()(const T& x, const T& y){return x > y;}};template<class T, class Container = vector<T>, class Compare = myless<T>>class priority_queue{public:// 强制编译器生成priority_queue() = default;template<class InputIterator>priority_queue(InputIterator first, InputIterator last){while (first != last){_con.push_back(*first);++first;}// 建堆for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--){adjust_down(i);}}void adjust_up(int child){Compare comfunc;int parent = (child - 1) / 2;while (child > 0){//if (_con[parent] < _con[child])if (comfunc(_con[parent], _con[child]))//if (comfunc.operator()(_con[parent], _con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){_con.push_back(x);adjust_up(_con.size() - 1);}void adjust_down(int parent){Compare comfunc;size_t child = parent * 2 + 1;while (child < _con.size()){//if (child + 1 < _con.size() && _con[child] < _con[child + 1])if (child + 1 < _con.size() && comfunc(_con[child], _con[child + 1])){++child;}//if (_con[parent] < _con[child])if (comfunc(_con[parent], _con[child])){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down(0);}const T& top(){return _con[0];}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};
}
//Test.cpp#include <iostream>
using namespace std;#include "PriorityQueue.h"void test_priority_queue()
{int a[] = { 3, 2, 7, 6, 0, 4, 1, 9, 8, 5 };// 默认是大堆//bit::priority_queue<int> q1(a, a + sizeof(a) / sizeof(int));// 小堆bit::priority_queue<int, vector<int>, bit::mygreater<int>> q1(a, a + sizeof(a) / sizeof(int));while (!q1.empty()){cout << q1.top() << " ";q1.pop();}cout << endl;
}int main()
{test_priority_queue();return 0;
}
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d) const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d) const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d);private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}void TestPriorityQueue()
{// 大堆,需要用户在自定义类型中提供<的重载bit::priority_queue<Date> q1;q1.push(Date(2018, 10, 29));q1.push(Date(2018, 10, 28));q1.push(Date(2018, 10, 30));while (!q1.empty()){cout << q1.top() << " ";q1.pop();}cout << endl;
}int main()
{TestPriorityQueue();return 0;
}
class Date
{
public:Date(int year = 1900,z int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d) const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d) const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d);private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}struct PDateLess
{bool operator()(Date* p1, Date* p2){return *p1 < *p2;}
};void TestPriorityQueue()
{// 大堆,需要用户在自定义类型中提供<的重载bit::priority_queue<Date*, vector<Date*>, PDateLess> q1;q1.push(new Date(2018, 10, 29));q1.push(new Date(2018, 10, 28));q1.push(new Date(2018, 10, 30));while (!q1.empty()){cout << *q1.top() << " ";q1.pop();}cout << endl;
}int main()
{TestPriorityQueue();return 0;
}