C++(stack和queue)

embedded/2024/10/21 23:46:02/

1. stack的介绍、使用和实现

1.1 stack的介绍

stl里的stack其实和数据结构内的stack和前面数据结构的栈不能说百分百一样,但也有百分之90是一样的,他们的特性都是LIFO(last in first out)先进后出的原则,前面有类似的这里就不过多讲述;

这个是C++ stack的文档:stack - C++ Reference (cplusplus.com)


1.2 stack的使用

stack的主要的使用接口就那么几个,我们这里就直接上个主要的接口图和使用的代码;如下图和代码所示:

#include<iostream>
#include<stack>
using namespace std;void TestStack()
{//同前面list一样,他们都是个模板stack<int> st;//empty的使用if (!st.empty()){cout << " stack is not empty" << endl;}else{cout << "stack is empty" << endl;}//push的使用st.push(1);st.push(2);st.push(3);st.push(4);st.push(5);//empty的使用if (!st.empty()){cout << " stack is not empty" << endl;}else{cout << "stack is empty" << endl;}//size的使用cout << "The size of stack is:> " << st.size() << endl;//top的使用cout << "The top element of stack is:> " << st.top() << endl;//因为栈和队列没有迭代器,如果有迭代器的话那就可以访问任意位置的数据了,//不符合后进先出的原则//所以如果我们想打印栈内的数据需要这样走;cout << "The element of stack are:> ";while (!st.empty()){cout << st.top() << " ";st.pop();}cout << endl;st.push(1);st.push(2);st.push(3);st.push(4);st.push(5);//pop的使用st.pop();st.pop();cout << "After pop the element of stack are:> ";while (!st.empty()){cout << st.top() << " ";st.pop();}
}int main()
{TestStack();return 0;
}

👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇

运行结果为:


1.3 stack的实现

由于在stl库内 stack不是一个简单的容器,而是一个容器适配器Container adaptor,举个例子,容器适配器就类似家里的插头,我们不仅可以用手机充电头去插头那给手机充电,还可以用电脑电源的充电头去给电脑充电,而手机充电头就类似list<int>,电脑充电头就类似vector<int>;如下代码可见;

#include<iostream>
#include<deque>
#include<stack>
#include<vector>
#include<list>
using namespace std;
//#include"stack.h"void teststack()
{//适配list容器stack<int, list<int>> st1;st1.push(1);st1.push(2);st1.push(3);st1.push(4);st1.push(5);cout << "The top is:> " << st1.top() << endl;st1.pop();st1.pop();cout << "The top is:> " << st1.top() << endl;while (!st1.empty()){cout << st1.top() << " ";st1.pop();}cout << endl;//适配vector容器stack<int, vector<int>> st2;st2.push(1);st2.push(2);st2.push(3);st2.push(4);st2.push(5);cout << "The top is:> " << st2.top() << endl;st2.pop();st2.pop();cout << "The top is:> " << st2.top() << endl;while (!st2.empty()){cout << st2.top() << " ";st2.pop();}
}
int main()
{teststack();return 0;
}

👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇

运行结果为:

那么我们实现stack的时候我们的类模板就不止一个传入的类型,还有一个类类型的变量接收;那具体的实现步骤就直接看代码,因为这个实现的底层其实也就是数组,但也可以用链表去实现前面数据结构的栈的篇章说过;如下代码所示:

#pragma once
#include"priority_queue.h"
#include<deque>
namespace lwt
{//stack在stl库内是被称作container adaptor(容器适配器)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()const{return _con.back();}size_t size()const{return _con.size();}bool empty()const{return _con.empty();}private:Container _con;};
}

这里的成员变量用Container就是为了达到容器适配器的效果,如果传入的是vector<int>,那么就会执行vector<int> _con; 然后再进行插入删除,list也一样;那上面有一点就是deque是什么玩意,先保留这个疑问,下面一会会讲到;


2. queue的介绍、使用和实现

2.1 queue的介绍

stl里的queue和数据结构里的queue队列也类似,也是先进先出FIFO的特性,所以也不过多讲述;

这个是C++的queue的文档:queue - C++ Reference (cplusplus.com)


2.2 queue的使用

如下图和代码所示:

#include<iostream>
#include<deque>
#include<queue>
#include<stack>
#include<vector>
#include<list>
using namespace std;int main()
{queue<int, list<int>> que1;que1.push(1);que1.push(2);que1.push(3);que1.push(3);que1.push(4);que1.push(5);while (!que1.empty()){cout << que1.front() << " ";que1.pop();}cout << endl;//size的使用que1.push(1);que1.push(2);que1.push(3);que1.push(3);que1.push(4);que1.push(5);cout << "The size of que1 is:> " << que1.size() << endl;que1.front() = 9;cout << "The front of que1 is:> " << que1.front() << endl;return 0;
}

👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇  👇

运行结果为:


2.3 queue的实现

stl库内的queue和上面的stack一样,都是容器适配器;增删查改实现的话其实就和前面的数据结构的队列实现的思路一样,所以不在这里过多讲述,直接上图和代码;

#pragma once
namespace lwt
{#include<deque>template<class T, class Container = deque<T> >class queue{public://入数据void push(const T& x){_con.push_back(x);}//出队列void pop(){_con.pop_front();}const T& front(){return _con.front();}const T& back(){return _con.back();}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};
}

3. deque的介绍

在上面我们看到stack和queue的模板的类类型的缺省参数是deque,但上面没有讲,因为我想在下面另外讲解;deque,可能我们看到有个que就认为他就是队列,所以底层可能是用链表实现的,其实并不然,deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高,也可以说deque是list和vector的杂交版;

但实质上,其实deque并不是真正的连续的空间,而是由一段段连续的小空间拼排而成的,实际上deque就类似一个动态的二维数组;其结构如下图所示:

红色区域是一个中控数组,每次的插入和删除都是在中控数组的中间开空间,这个效率就很高了,为什么高呢?相比于链表,他的尾插和头插的效率更高,因为他每次都是开绿色块那样的空间大小,而链表每次头尾插需要进行开辟新的空间,开辟新的空间会造成效率降低;对于vector来说,头插就很方便了,他只需要在前面再new多一块空间,然后从后往前插入完成头插,而不需要挪动数据,

下图是他的具体结构

3.1 deque的缺陷

当deque遍历的时候要频繁的检测first是否等于last,如果等于就需要node+1,导致效率低下,所以一般要使用线性结构的时候大多数优先考虑list和vector,deque的应用场景不多,目前看见的应用是在STL里用其作为stack和queue的底层结构;

3.2 为什么选择deque作为stack和queue的底层结构

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

4. priority_queue的介绍和实现

4.1 priority_queue的介绍

        priority_queue又称优先级队列,它的第一个元素总是它所包含的元素中最大的,那这是不是就有点像我们前面数据结构学过的堆;其实优先级队列的底层就是堆,首先我们先来回忆一下堆的性质,堆分为大堆和小堆,大堆的每个树的父节点是树中最大的,小堆则反之,但是STL的priority_queue和我们数据结构那实现的堆的不同是,他是一个容器适配器,即只要符合他的特性的容器都可以拿来当他的底层,如下图就是优先级队列的特性;

而标准类vector和deque满足这些条件;还需要支持随机访问迭代器,因为完成建堆等操作,而 堆的底层就是顺序表,那就需要支持随机访问迭代器;


4.2 仿函数基础

在实现优先级队列之前我们还需要提一个点就是仿函数,仿函数顾名思义就是类似函数的东西,他实质上是一个类,他是重载了“()”的一个类,作用是用来做比较,例如如果我们想实现一个大堆的话,我们就需要修改建堆的大于小于号,那是不是太麻烦了,所以我们就延伸出了仿函数这个东西;举个例子,比如说我想让条件为arr[parent]>arr[child]的时候我们就可以定义一个类作为仿函数greater(arr[parent], arr[child] ),而我我想让条件改为arr[parent]<arr[child]的话就定义一个类作为仿函数less(arr[parent], arr[child];如下代码可见,这是使用,就需要在创建priority_queue的时候在最后面加一个greater<int>;

#include <vector>
#include <queue>
#include<iostream>
#include <functional> // greater算法的头文件
using namespace std;void TestPriorityQueue()
{// 默认情况下,创建的是大堆,其底层按照小于号比较vector<int> v{ 3,2,7,6,0,4,1,9,8,5 };priority_queue<int> q1;for (auto& e : v)q1.push(e);cout << q1.top() << endl;// 如果要创建小堆,将第三个模板参数换成greater比较方式priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());cout << q2.top() << endl;
}int main()
{TestPriorityQueue();return 0;
}

4.2 priority_queue的实现

优先级队列的实现也很简单,其实就是建堆,只不过在这里面添加多了一个仿函数进行判断是建小堆还是大堆,如下代码所示:

#pragma once
#include<vector>
template<class T>
class Less
{
public:bool operator()(const T& x, const T& y){return x < y;}
};template<class T>
class Greater
{
public:bool operator()(const T& x, const T& y){return x > y;}
};namespace lwt
{template<class T, class Container = vector<T> , class Compare = Less<T>>class priority_queue{public:void AdjustUp(int child){Compare  com;int parent = (child - 1) / 2;while (child > 0){if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;	}}}void push(const T& x){_con.push_back(x);AdjustUp(_con.size()-1);}void AdjustDown(int parent){size_t child = parent * 2 + 1;Compare com;while (child < _con.size()){//看左右孩子谁大谁小,大堆那我们就要找到小的if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){++child;}if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){//pop就是堆删swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}const T& top(){return _con[0];}size_t size() const{return _con.size();}bool empty()const{return _con.empty();}private:Container _con;};}

END!


http://www.ppmy.cn/embedded/129400.html

相关文章

论新能源智能化电动车个性化(高定)产品对制造生产的影响

一、新能源智能化电动车高定体现模式 1.个性体现在品牌之间 在不同主机产产品上体现&#xff0c;例如国产新能源新势力在智能座舱、内饰配置&#xff08;冰箱、彩电、大沙发&#xff09;方面对于合资品牌的碾压&#xff0c;提供更多细分&#xff0c;功能拉满的车型。 2.个性化…

C#从零开始学习(继承)(6)

本章所有的代码都放在 https://github.com/hikinazimi/head-first-Csharp 使用冒号继承一个基类,子类扩展一个基类时,他会继承它的成员:也就是基类中的所有字段,属性和方法,他们会自动增加到子类 子类覆盖方法改变它继承的成员 基类中的方法增加virtual关键字子类同名方法增加…

自动化运维:高效IT管理的未来

自动化运维&#xff1a;高效IT管理的未来 在信息技术日新月异的时代&#xff0c;你是否曾思考过&#xff0c;为什么许多企业面临的运维挑战日益严峻&#xff1f;传统的运维方式&#xff0c;像是使用手动工具修理老旧机器&#xff0c;既耗时又容易出错。随着企业对高效、安全的…

docker harbor

文章目录 一&#xff0c;搭建私有仓库1.1下载registry1.2在 daemon.json 中添加私有镜像仓库地址1.3重新加载重启docker1.4运行容器1.5拉取一个centos7镜像1.6给镜像加标签1.7上传镜像1.8显示私有仓库的所有镜像1.8查看私有仓库的 centos 镜像有哪些tag 二&#xff0c;什么是ho…

Go Wails 学习笔记:创建第一个项目

文章目录 1. 安装 Wails2. 创建 Wails 项目3. 项目结构4. 运行项目5. 构建项目6. 部署和发布总结 Wails 是一个用于构建跨平台桌面应用程序的框架&#xff0c;允许开发者使用前端技术&#xff08;如 HTML、CSS、JavaScript&#xff09;以及 Go 语言来开发桌面应用。本文基于官方…

C语言 sizeof 的介绍,以及sizeof计算数组名、 数组首地址、数组的元素之间的区别

一、sizeof 介绍 sizeof 是 C 语言中的一个运算符&#xff0c;用于计算数据类型或变量在内存中占用的字节数。用于计算数据类型或变量所占的内存大小&#xff0c;以字节为单位。它可以在编译时计算其操作数的大小&#xff0c;并返回一个 size_t 类型的值。它可以帮助了解不同类…

168K+ Star!AutoGPT:一个构建、部署和运行AI代理的强大平台

AutoGPT 简介 AutoGPT[1] 是一个强大的平台&#xff0c;它允许用户创建、部署和管理持续运行的AI代理&#xff0c;以自动化复杂的工作流程。 该项目的使命是提供工具&#xff0c;让用户能够专注于重要的事情。 项目特点 主要特点 Agent Builder&#xff1a;一个直观的低代码…

【git】如何快速准确的回退(revert)已经合并(merge)主分支(master)的新提交代码

文章目录 前言一、merge模式二、回滚步骤总结 前言 我们在做一些需求&#xff0c;正常流程经过开发&#xff0c;测试到最后和代码上线。但是有时候就会发生一些小插曲&#xff0c;比如产品说老板说某某某你的代码要延后上线&#xff01;&#xff01;或者你写的不合格预发环境出…