链式栈StackT
C++关键词:内部类/模板类/头插
C++自学精简教程 目录(必读)
C++数据结构与算法实现(目录)
栈的内存结构
空栈:
有一个元素的栈:
多个元素的栈:
成员函数说明
0 clear 清空栈
clear 函数负责将栈的对内存释放,成员初始化为初始值,比如指针为空指针,计数成员变量赋0值。
1 copy 从另一个栈拷贝
copy 函数可以给 拷贝构造函数调用,也可以被 赋值操作调用。
由于拷贝构造函数发生在构造阶段,对象刚刚创建,不可能有内容,而赋值操作符就不一定了。
对象被赋值的时候,可能已经有元素了,所以这时候copy 内部需要先调用 clear 成员函数来清空自己管理的堆内存。让对象重新回到一个空的栈状态。
2 pop 弹出栈顶元素
pop 执行的时候,不需要检查栈是否为空。用户应该去调用 empty来检查栈是否为空。
或者用户确定调用pop的时候栈是不可能为空的,这样就避免了不必要的代码的执行。
这样做的注意目的是为了效率,类的接口各司其职,分工明确。
接口与测试用例
#include <iostream>
#include <iomanip>//------下面的代码是用来测试你的代码有没有问题的辅助代码,你无需关注------
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <utility>
using namespace std;
struct Record { Record(void* ptr1, size_t count1, const char* location1, int line1, bool is) :ptr(ptr1), count(count1), line(line1), is_array(is) { int i = 0; while ((location[i] = location1[i]) && i < 100) { ++i; } }void* ptr; size_t count; char location[100] = { 0 }; int line; bool is_array = false; bool not_use_right_delete = false; }; bool operator==(const Record& lhs, const Record& rhs) { return lhs.ptr == rhs.ptr; }std::vector<Record> myAllocStatistic; void* newFunctionImpl(std::size_t sz, char const* file, int line, bool is) { void* ptr = std::malloc(sz); myAllocStatistic.push_back({ ptr,sz, file, line , is }); return ptr; }void* operator new(std::size_t sz, char const* file, int line) { return newFunctionImpl(sz, file, line, false); }void* operator new [](std::size_t sz, char const* file, int line)
{return newFunctionImpl(sz, file, line, true);
}void operator delete(void* ptr) noexcept { Record item{ ptr, 0, "", 0, false }; auto itr = std::find(myAllocStatistic.begin(), myAllocStatistic.end(), item); if (itr != myAllocStatistic.end()) { auto ind = std::distance(myAllocStatistic.begin(), itr); myAllocStatistic[ind].ptr = nullptr; if (itr->is_array) { myAllocStatistic[ind].not_use_right_delete = true; } else { myAllocStatistic[ind].count = 0; }std::free(ptr); } }void operator delete[](void* ptr) noexcept { Record item{ ptr, 0, "", 0, true }; auto itr = std::find(myAllocStatistic.begin(), myAllocStatistic.end(), item); if (itr != myAllocStatistic.end()) { auto ind = std::distance(myAllocStatistic.begin(), itr); myAllocStatistic[ind].ptr = nullptr; if (!itr->is_array) { myAllocStatistic[ind].not_use_right_delete = true; } else { myAllocStatistic[ind].count = 0; }std::free(ptr); } }
#define new new(__FILE__, __LINE__)
struct MyStruct { void ReportMemoryLeak() { std::cout << "Memory leak report: " << std::endl; bool leak = false; for (auto& i : myAllocStatistic) { if (i.count != 0) { leak = true; std::cout << "leak count " << i.count << " Byte" << ", file " << i.location << ", line " << i.line; if (i.not_use_right_delete) { cout << ", not use right delete. "; } cout << std::endl; } }if (!leak) { cout << "No memory leak." << endl; } }~MyStruct() { ReportMemoryLeak(); } }; static MyStruct my; void check_do(bool b, int line = __LINE__) { if (b) { cout << "line:" << line << " Pass" << endl; } else { cout << "line:" << line << " Ohh! not passed!!!!!!!!!!!!!!!!!!!!!!!!!!!" << " " << endl; exit(0); } }
#define check(msg) check_do(msg, __LINE__);
//------上面的代码是用来测试你的代码有没有问题的辅助代码,你无需关注------//2020-07-09
template<typename T>
class Stack
{
public:Stack(void);Stack(const Stack& _stack);Stack& operator=(const Stack& _stack);~Stack(void);public:inline const T& top(void) const;inline bool empty(void) const;inline size_t size(void) const;void push(const T& _item);void pop(void);void clear(void);
private:void copy(const Stack& stack1);
private:struct CStackitem{public:CStackitem(void);CStackitem(const T& _data, CStackitem* next = nullptr);public:CStackitem(CStackitem& _item) = delete;// = delete 表示禁止编译器生成默认版本的函数,主要用来禁止该类型对象拷贝CStackitem& operator=(CStackitem& _item) = delete;public:CStackitem* next = nullptr;//这里的初始化会在所有构造函数执行之前先执行,所以构造函数里就不用再对该成员初始化了T data;};
private:CStackitem m_head;//注意这里不是指针类型size_t m_size = 0;
};template<typename T>
Stack<T>::CStackitem::CStackitem(void)
//(1) your code 对1个成员变量初始化{
}template<typename T>
Stack<T>::CStackitem::CStackitem(const T& _data, CStackitem* _next):data(_data), next(_next)
{
}
template<typename T>
Stack<T>::Stack(void)
//(3) your code 对1个成员变量初始化{
}template<typename T>
Stack<T>::Stack(const Stack& _stack)
{//(4) your code 使用 copy 即可}template<typename T>
Stack<T>& Stack<T>::operator=(const Stack& _stack)
{//(5) your code 记得判断同一个对象赋值给自己return *this;
}template<typename T>
Stack<T>::~Stack(void)
{clear();
}
template<typename T>
bool Stack<T>::empty(void) const
{return m_size == 0;
}
template<typename T>
void Stack<T>::pop(void)
{//(9) your code 注意对象获取成员用"."操作符,指针获取成员用"->"操作符}
template<typename T>
void Stack<T>::clear(void)
{//(6) your code 可以利用 pop 来实现}
template<typename T>
void Stack<T>::copy(const Stack& from)
{//(7) your code 请先使用 clear ,再遍历链表来实现}
template<typename T>
size_t Stack<T>::size(void) const
{return m_size;
}
template<typename T>
void Stack<T>::push(const T& item)
{//(8) your code, 注意 这样写新创建的节点 CStackitem* p = new CStackitem(item, first);}
template<typename T>
const T& Stack<T>::top(void) const
{return m_head.next->data;
}int main(int argc, char** argv)
{Stack<int> stack1;check(stack1.size() == 0);stack1.push(1);check(stack1.size() == 1);auto stack2 = stack1;auto top = stack2.top();check(top == 1);check(stack2.size() == 1);stack1 = stack2;// 1 and 1stack1.push(2);// 2 1top = stack2.top();check(top == 1);check(stack1.size() == 2);check(stack1.top() == 2);stack1.clear();check(stack1.size() == 0 && stack1.empty());for (size_t i = 0; i < 10; i++){stack1.push(i);}while (!stack1.empty()){std::cout << stack1.top() << " ";stack1.pop();}cout << endl;check(stack1.size() == 0 && stack1.empty());//copy constructor{Stack<int> from;from.push(1);from.push(2);Stack<int> to(from);check(to.size() == 2);check(to.top() == 2);to.pop();check(to.top() == 1);to.pop();check(to.empty());}
}
输出:
line:155 Pass
line:157 Pass
line:160 Pass
line:161 Pass
line:165 Pass
line:166 Pass
line:167 Pass
line:169 Pass
9 8 7 6 5 4 3 2 1 0
line:180 Pass
line:188 Pass
line:189 Pass
line:191 Pass
line:193 Pass
Memory leak report:
No memory leak.
还没完!
现在我们来思考一个更具价值的问题:栈有必要重新实现一次吗?答案是否定的。
回忆我们之前的工作,我们实现了动态数组vector和链表list,这两个容器都支持在末尾增加和删除元素。
这正是栈的功能。
也就是说我们其实已经实现过栈了。
我们可以直接把动态数组和链表替换任何需要栈的地方,只不过类型的名字还不叫栈而异。
那么我们该怎么做才比较好呢?
那就是利用已经实现的容器包装出另一个容器。具体做法就是,假如我们打算用链表来实现栈(当然用数组实现也是类似的)。
可以把一个链表对象作为栈的成员变量。
对栈的操作都通过栈的成员函数转发给这个链表来做。
这种做法的好处:
(1)稳定!稳定!稳定!
因为链表的实现中有大量的细节,很容易出错。如果我们也在链表中再来一遍的话,指不定又会写出bug来。这在正式开发环境中代价是极其高昂的。没有客户愿意接受一个经常喜欢出洋相的产品。
让测试人员从头开始测试一遍产品他们的工作量几乎要翻倍。这会极大的资源浪费。竞争对手可能已经跑在了前面。
原来对链表的测试用例已经把链表的稳定性保证了,所以现在的不确定性只是在栈对链表的包装上。
由于包装的代码就是接口转发,只要类型写对,接口名别调用错了就可以了,所以出问题的概率极大的降低了。
这种以基础容器制造其他容器的做法在软件开发中叫模块化封装。
链表是一个模块,栈的是一个模块。用链表封装出了一个栈。
(2)减少开发工作量
由于使用了现成的代码,所以有些底层的代码直接拿来用,这就节省了工作量。提高了开发效率。
祝你好运!
答案在此
链式栈StackT(答案)_C++开发者的博客-CSDN博客
相关文章:

链式栈StackT
C关键词:内部类/模板类/头插 C自学精简教程 目录(必读) C数据结构与算法实现(目录) 栈的内存结构 空栈: 有一个元素的栈: 多个元素的栈: 成员函数说明 0 clear 清空栈 clear 函数负责将栈的对内存释放…...

Fiddler中 AutoResponder 使用
Fiddler的 AutoResponder ,即URL重定向功能非常强大。不管我们做URL重定向,还是做mock测试等,都可以通过该功能进行实践。 下面,小酋就来具体讲下该功能的用法。 Enable rules 启用规则Unmatched requests passthrough 没有匹配…...

77GHz线性调频连续波雷达
文章目录 前言 一、背景 二、优缺点 三、工作原理 四、电路模块设计 4.1.LFMCW信号源 4.2.发射电路 4.3.接收电路 4.4.信号处理器 五、应用 5.1.汽车测距 5.2.军事方面 5.3.气象方面 总结 前言 这篇文章是博主本科期间整理的关于77GHz线性调频连续波雷达的相关资料,…...

YOLOV8改进:更换为MPDIOU,实现有效涨点
1.该文章属于YOLOV5/YOLOV7/YOLOV8改进专栏,包含大量的改进方式,主要以2023年的最新文章和2022年的文章提出改进方式。 2.提供更加详细的改进方法,如将注意力机制添加到网络的不同位置,便于做实验,也可以当做论文的创新点。 2.涨点效果:更换为MPDIOU,实现有效涨点! 目录…...

BookStack开源免费知识库docker-compose部署
BookStack(书栈)是一个功能强大且易于使用的开源知识管理平台,适用于个人、团队或企业的文档协作和知识共享。 一、BookStack特点 简单易用:BookStack提供了一个直观的用户界面,使用户能够轻松创建、编辑和组织文档多…...

Linux:编译遇到 Please port gnulib freadahead.c to your platform ,怎么破
问题背景 编译m4时遇到以下错误,该怎么解决呢? 解决方法 进入m4的build目录:build/host-m4-1.4.17 输入命令: sed -i s/IO_ftrylockfile/IO_EOF_SEEN/ lib/*.c echo "#define _IO_IN_BACKUP 0x100" >> lib/std…...

three.js(三):three.js的渲染结构
three.js 的渲染结构 概述 three.js 封装了场景、灯光、阴影、材质、纹理和三维算法,不必在直接用WebGL 开发项目,但有的时候会间接用到WebGL,比如自定义着色器。three.js 在渲染三维场景时,需要创建很多对象,并将它…...

客户端读写HBase数据库的运行原理
1.HBase的特点 HBase是一个数据库,与RDMS相比,有以下特点: ① 它不支持SQL ② 不支持事务 ③ 没有表关系,不支持JOIN ④ 有列族,列族下可以有上百个列 ⑤ 单元格,即列值,可以存储多个版本的值&…...

不使用VH6501设备,通过VN1630等普通设备使用canConfigureBusOff函数进行busoff干扰测试
** 特别注意一下,使用这个函数需要你的vector驱动在9.6以上以及支持 ISO CAN FD. ** 函数canConfigureBusOff 可以通过脚本的形式产生bus off,而VH6501可以通过干扰bit位来产生bus off(使用CANoe Demo - CANDisturbanceMain进行Bus Off测试)。 对于函数canConfigureBusOf…...

服务器数据恢复-服务器RAID6硬盘故障离线的数据恢复案例
服务器数据恢复环境: 服务器中有一组由6块磁盘组建的RAID6磁盘阵列。服务器作为WEB服务器使用,上面运行了MYSQL数据库以及存放了网站代码和其他数据文件。 服务器故障: 在服务器运行过程中该raid6阵列中有两块磁盘先后离线,但是管…...
DB2 HADR+TSA运维,TSA添加资源组的命令
Tivoli System Automation(TSA)是一个高可用性集群管理软件,DB2 TSAHADR高可用方案可以实现DB2 hadr主备的自动检测切换。本文详细介绍了TSA的常用命令,如何把CDC或者DSG添加到TSA集群中,以及TSA的错误分析方法 常用命令…...
LeetCode-135-分发糖果
题目描述:n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需要按照以下要求,给这些孩子分发糖果: 每个孩子至少分配到 1 个糖果。 相邻两个孩子评分更高的孩子会获得更多的糖果。 请你给每个孩子分发糖果,计…...
Viva Workplace Analytics Employee Feedback SU Viva Glint部署方案
目录 一、Viva Workplace Analytics & Employee Feedback SU Viva Glint介绍 二、Viva Glint和Viva Pulse特点和优势 1. 简单易用...
ASIC-WORLD Verilog(14)系统任务
写在前面 在自己准备写一些简单的verilog教程之前,参考了许多资料----Asic-World网站的这套verilog教程即是其一。这套教程写得极好,奈何没有中文,在下只好斗胆翻译过来(加点自己的理解)分享给大家。 这是网站原文&…...

两台电脑共享文件设置
步骤一:确保网络连接正常,可网线直连。 两台电脑IP设置,例: 步骤二:启用共享功能。 1.在【控制面板】中选择【网络和Internet】; 2.点击【网络和共享中心】,在左侧导航栏中,点击【…...
《C和指针》笔记17:sizeof
sizeof操作符判断它的操作数的类型长度,以字节为单位表示。 操作数既可以是个表达式(常常是单个变量), sizeof x上面的式子返回变量x所占据的字节数。 也可以是两边加上括号的类型名。 sizeof(int)上面的式子返回整型变量的字…...

说说大表关联小表
分析&回答 Hive 大表和小表的关联 优先选择将小表放在内存中。小表不足以放到内存中,可以通过bucket-map-join(不清楚的话看底部文章)来实现,效果很明显。 两个表join的时候,其方法是两个join表在join key上都做hash bucket,…...

Unity 之 方括号[ ] 的用法以及作用
文章目录 在Unity中,方括号 [ ] 通常用于表示属性、特性(Attributes)或者元数据(Metadata)。这些标记提供了附加信息,可以用于修改类、方法、字段等的行为或者在编辑器中进行设置。 以下是一些常见的用法&…...
微服务nacos或者yml配置内容部分加密jasypt
写在最前:因业务需要把nacos配置中的部分密码加密,不能暴露在外,本想用nacos官方的插拔插件nacos-aes-encryption-plugin的,但是比较复杂且官方文档说的不清不楚所以弃用,有兴趣的可以参考。链接:https://n…...

Vue:插槽,与自定义事件
1.插槽slot <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <div id"app"><!-- <p>列表书籍</p>--> <!-- …...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...