当前位置: 首页 > news >正文

stack 和 queue

文章目录

    • 1. stack的使用
    • 2. queue的使用
    • 3. stack的模拟实现
    • 4. queue的模拟实现
    • 5. deque的简单介绍
    • 6. priority_queue的使用
    • 7. priority_queue的模拟实现

1. stack的使用

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的使用

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类似于一个动态的二维数组,其底层结构如下图所示:

deque(1)

#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(2)
deque(3)


为什么选择deque作为stack和queue的底层默认容器:

stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如list。

但是STL中对stack和queue默认选择deque作为其底层容器,主要是因为:

  1. stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
  2. 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高。

结合了deque的优点,而完美的避开了其缺陷。

6. priority_queue的使用

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;
}
http://www.dtcms.com/a/392603.html

相关文章:

  • 执行yarn init报错:error Invalid package name.(question name)包名格式不对
  • Windows 下 PyTorch 入门深度学习环境安装与配置 CPU GPU 版 | 土堆教程
  • Transformer中为什么要使用多头注意力?
  • 《嵌入式硬件(十六):基于IMX6ULL的I2C的操作》
  • AI.工作助手.工作提效率
  • 【开题答辩全过程】以 Louis宠物商城为例,包含答辩的问题和答案
  • 微服务-网络模型与服务通信方式openfein
  • 如何快速定位局域网丢包设备?
  • 算法<java>——排序(冒泡、插入、选择、归并、快速、计数、堆、桶、基数)
  • 深入浅出CMMI:从混乱到卓越的研发管理体系化之路
  • Docker一键部署prometheus并实现飞书告警详解
  • 基于“开源AI大模型AI智能名片S2B2C商城小程序”的多平台资源位传播对直播营销流量转化的影响研究
  • 【设计模式】适配器模式 在java中的应用
  • 2013/07 JLPT听力原文 问题四
  • MyBatis 缓存体系剖析
  • MySQL 主从复制 + MyCat 读写分离 — 原理详解与实战
  • Vmake AI:美图推出的AI电商商品图编辑器,快速生成AI时装模特和商品图
  • Debian13 钉钉无法打开问题解决
  • 02.容器架构
  • Diffusion Model与视频超分(1):解读淘宝开源的视频增强模型Vivid-VR
  • 通过提示词工程(Prompt Engineering)方法重新生成从Ollama下载的模型
  • 有没有可以检测反爬虫机制的工具?
  • 大模型为什么需要自注意力机制?
  • 长度为K子数组中的最大和-定长滑动窗口
  • Linux安装Kafka(无Zookeeper模式)保姆级教程,云服务器安装部署,Windows内存不够可以看看
  • WEEX编译|续写加密市场叙事
  • 为 Element UI 表格增添排序功能
  • 点评项目(Redis中间件)第四部分缓存常见问题
  • 动态水印也能去除?ProPainter一键视频抠图整合包下载
  • DevSecOps 意识不足会导致哪些问题