C++之stack 和 queue

ops/2024/9/25 23:21:00/

目录

前言

1.stack的介绍和使用

1.1 stack的介绍

1.2 stack的使用

1.3 stack 的模拟

2. queue的介绍和使用

2.1 queue的介绍

 2.2 queue的使用

2.3 queue的模拟

3.适配器

3.1 什么是适配器

3.2 STL标准库中stack和queue的底层结构

3.3 deque 的介绍(了解)

3.3.1 deque的原理

3.3.2 deque 的缺陷

3.4 STL标准库中对于stack和queue的模拟实现

3.4.1 stack 的模拟

3.4.2 queue 的模拟

测试代码参考

结束语


前言

数据结构部分我们通过C实现了栈和队列,本节我们将了解C++版本下的

stack和queue。我们将会很轻松的学习这部分知识。

1.stack的介绍和使用

1.1 stack的介绍

 后进先出

1.2 stack的使用

函数加接口说明 函数加接口说明
stack()    构造空的栈   empty()检测stack是否为空
size()返回stack中元素的个数  top()返回栈顶元素的引用
push()将元素val压入stack中   pop()将stack中尾部的元素弹出 

void test_stack() {stack<int>s1;s1.push(1);s1.push(2);s1.push(3);s1.push(4);s1.push(5);cout << s1.size() << endl;cout << s1.top() << endl;s1.pop();cout << s1.top() << endl;
}

1.3 stack 的模拟

stack我们是先进先出,并从栈的接口中可以看出,栈实际是一种特殊的vector,因此使用vector完全可以模拟实现stack。

我们将vector设为私有成员

#include <vector>
namespace my_stack {template <class T>class stack {public:stack() {}void push(const T& x) {c.push_back(x);}void pop() {c.pop_back();}const T& top() {return c.back();}size_t size()const {return c.size();}bool empty()const {return c.empty();}private:std::vector<T> c;};
}

这样子实现有个缺陷,如果我们需要实现一个链式栈就无法,可能会想到改成list,但是很麻烦。

我们可以导入一个容器类来进行实现。在后面的适配器我们会讲到。

2. queue的介绍和使用

2.1 queue的介绍

 

1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元 素,另一端提取元素。

2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供 一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。

3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。

该底层容器应至少 支持以下操作:

empty:检测队列是否为空    size:返回队列中有效元素的个数

front:返回队头元素的引用   back:返回队尾元素的引用

push_back:在队列尾部入队列    pop_front:在队列头部出队列

4. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。 

 2.2 queue的使用

void test_queue() {queue<int>q1;q1.push(1);q1.push(2);q1.push(3);q1.push(4);q1.push(5);cout << q1.size() << endl;cout << q1.front() << endl;cout << q1.back() << endl;q1.pop();cout << q1.front() << endl;}

2.3 queue的模拟

因为queue的接口中存在头删和尾插,因此使用vector来封装效率太低,故可以借助list来模拟实 现queue。

#include <list>
namespace my_queue {template <class T>class queue {public:queue() {}void push(const T& x) {c.push_back(x);}void pop() {c.pop_back();}T& back()  {return  c.back();}T& front() const return  c.front();}size_t size()const {return c.size();}bool empty()const {return c.empty();}private:std::list<T> c;};
}

通过官方的queue和stack我们可以看到,在类模版中都定义了一个class Container=deque<T>;

所以我们同样类似这样子写,在后续我们会讲解deque的知识。

namespace my_stack {template <class T,class Container=vector<T>>class stack {public:stack() {}void push(const T& x) {con.push_back(x);}void pop() {con.pop_back();}const T& top() {return con.back();}size_t size()const {return con.size();}bool empty()const {return con.empty();}const T& front() const{return con.front();}const T& back() const{return con.back();}private:Container con;};
}

这样我们既可以写顺序栈也可以链式栈

my_stack::stack<int,vector<int>>s1;

my_stack::stack<int,list<int>>s1;

这里我们使用了vector来当默认参数,而在方法中却穿插了链表的方法,编译时却没有报错,这是因为这是类模版,在主函数类模板实例化时,按需实例化,使用哪些成员函数就实例化哪些,不会全实例化,所以当我们使用vector的时候,不调用list的方法就行了

#include <list>
namespace my_queue {template<class T, class Container = list<T>>class queue{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}const T& front() const{return _con.front();}const T& back() const{return _con.back();}size_t size() const{return _con.size();}bool empty() const{return _con.empty();}private:Container _con;};
}

3.适配器

3.1 什么是适配器

适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设 计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。

3.2 STL标准库中stack和queue的底层结构

虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为 容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装,STL中stack和queue默认 使用deque,比如:

3.3 deque 的介绍(了解)

3.3.1 deque的原理

deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端 进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与 list比较,空间利用率比较高。

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个 动态的二维数组,其底层结构如下图所示:

双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问 的假象,落在了deque的迭代器身上,因此deque的迭代器设计就比较复杂,如下图所示: 

那deque是如何借助其迭代器维护其假想连续的结构呢? 如下图所示

3.3.2 deque 的缺陷

与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩 容时,也不需要搬移大量的元素,因此其效率是必vector高的。

与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。

但是,deque不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其 是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实 际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多,

而目前能看到的一个应用就是,STL用其作为stack和queue的底层数据结构 

为什么选择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不仅效率高,而且内存使用率高。

3.4 STL标准库中对于stack和queue的模拟实现

3.4.1 stack 的模拟

#include<deque>
namespace my_stack
{template<class T, class Con = deque<T>>//template<class T, class Con = vector<T>>//template<class T, class Con = list<T>>class stack{public:stack() {}void push(const T& x){ _c.push_back(x); }void pop() { _c.pop_back(); }T& top() { return _c.back(); }const T& top()const { return _c.back(); }size_t size()const { return _c.size(); }bool empty()const { return _c.empty(); }private:Con _c;};
}

3.4.2 queue 的模拟

#include<deque>
#include <list>
namespace my_queue
{template<class T, class Con = deque<T>>//template<class T, class Con = list<T>>class queue{public:queue() {}void push(const T& x) {_c.push_back(x); }void pop() {_c.pop_front(); }T& back() { return _c.back(); }const T& back()const { return _c.back(); }T& front() { return _c.front(); }const T& front()const { return _c.front(); }size_t size()const { return _c.size(); }bool empty()const { return _c.empty(); }private:Con _c;};
}

测试代码参考

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
#include "stack.h"
#include "queue.h"
void print() {}
void test_stack() {stack<int>s1;s1.push(1);s1.push(2);s1.push(3);s1.push(4);s1.push(5);cout << s1.size() << endl;cout << s1.top() << endl;s1.pop();cout << s1.top() << endl;
}
void test_queue() {queue<int>q1;q1.push(1);q1.push(2);q1.push(3);q1.push(4);q1.push(5);cout << q1.size() << endl;cout << q1.front() << endl;cout << q1.back() << endl;q1.pop();cout << q1.front() << endl;}
int main() {//test_stack();//test_queue();/*my_stack::stack<int,list<int>>s1;s1.push(1);s1.push(2);s1.push(3);s1.push(4);s1.push(5);cout << s1.size() << endl;cout << s1.top() << endl;s1.pop();cout << s1.top() << endl;cout << s1.back() << endl;cout << s1.front() << endl;*/my_queue::queue<int> q1;q1.push(1);q1.push(2);q1.push(3);q1.push(520);q1.push(1314);cout << q1.back() << endl;cout << q1.front() << endl;q1.pop();cout << q1.back() << endl;cout << q1.front() << endl;my_stack::stack<int> q2;q2.push(1);q2.push(2);q2.push(3);q2.push(520);q2.push(1314);cout << q2.top() << endl;cout << q2.top()<< endl;q2.pop();cout << q2.top() << endl;const my_stack::stack<int>& crefMyStack = q2;cout << "Top element (const) is: " << crefMyStack.top() << endl;return 0;
}

结束语

本次博客内容就到此结束了。理所当然C++下的stack和queue的实现更加的简便和多种多样!

最后感谢各位友友们的捧场和支持,给小编留个赞吧!!!


http://www.ppmy.cn/ops/115994.html

相关文章

llamafactory0.9.0微调qwen2.5

llama_factory微调QWen1.5_llama factory qwen-CSDN博客文章浏览阅读2.9k次,点赞36次,收藏10次。本文介绍了如何使用LLaMA-Factory微调Qwen1.5模型,包括1.8B和0.5B版本的训练细节。在数据、训练、LORA融合及推理等方面进行了探讨,同时也分享了微调后模型在不同任务上的表现…

C++ STL全面解析:六大核心组件之一----序列式容器(vector和List)(STL进阶学习)

目录 序列式容器 Vector vector概述 vector的迭代器 vector的数据结构 vector的构造和内存管理 vector的元素操作 List List概述 List的设计结构 List的迭代器 List的数据结构 List的内存构造 List的元素操作 C标准模板库&#xff08;STL&#xff09;是一组高效的…

Go weak包前瞻:弱指针为内存管理带来新选择

在介绍Go 1.23引入的unique包的《Go unique包&#xff1a;突破字符串局限的通用值Interning技术实现》一文中&#xff0c;我们知道了unique包底层是基于internal/weak包实现的&#xff0c;internal/weak是一个弱指针功能的Go实现。所谓弱指针(Weak Pointer&#xff0c;也称为弱…

npm包管理工具

npm&#xff08;全称 Node Package Manager&#xff0c;即node包管理器&#xff09;Node.js默认的、JavaScript编写的软件包管理系统。 npm常见命令 # 项目开发相关 npm init # 在项目根目录下&#xff0c;创建一个 package.json 文件,需要填写一些内容 npm init -y …

mac终端打开报complete 13 command not found compdef异常处理以及命令补全功能实现

mac终端报complete未找到异常 mac打开终端报如下错误 "complete:13: command not found: compdef" message when launching Terminal 问题处理&#xff0c;参考https://apple.stackexchange.com/questions/296477/my-command-line-says-complete13-command-not-fou…

快速理解TCP协议(二)——TCP协议中的拥塞控制机制详解

在计算机网络中&#xff0c;TCP&#xff08;传输控制协议&#xff09;是一种广泛使用的面向连接的、可靠的、基于字节流的传输层通信协议。TCP协议通过一系列复杂的机制来确保数据的可靠传输&#xff0c;其中拥塞控制是至关重要的一环。本文将深入探讨TCP协议中的拥塞控制机制&…

keil的debug功能

文章目录 一.窗口介绍二.功能2.1 debug断点调试和窗口变量2.2 四个花括号功能2.2.1 进去函数和下一步功能2.2.2 跳过函数和跳过该行代码功能2.2.3 函数内部跳出功能2.2.4 执行到光标处 2.3 查看内部寄存器 一.窗口介绍 二.功能 2.1 debug断点调试和窗口变量 先打开下图debug断…

量子密码基本原理和必要性

量子加密 量子加密&#xff08;Quantum Encryption&#xff09;&#xff0c;或称量子密码&#xff0c;是一种基于量子力学原理的加密技术。它通过自然物理定律而非数学模型保障信息安全。与传统的加密算法不同&#xff0c;量子加密具有理论上的不可破解性&#xff0c;因为其安…