链式栈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>--> <!-- …...
Serilog:从结构化日志认知到 .NET 工程落地
MySQL 中的 count 三兄弟:效率大比拼! 一、快速结论(先看结论再看分析) 方式 作用 效率 一句话总结 count(*) 统计所有行数 最高 我是专业的!我为统计而生 count(1) 统计所有行数 同样高效 我是 count(*) 的马甲兄弟…...
YOLO-v5实战:用预训练模型快速检测图片中的物体
YOLO-v5实战:用预训练模型快速检测图片中的物体 1. 引言:为什么选择YOLO-v5 在计算机视觉领域,物体检测是一项基础而重要的任务。YOLO(You Only Look Once)系列模型因其速度快、精度高的特点,成为工业界和…...
Calypso vs PC-DMIS:三坐标两大软件脱机编程实战对比与选型指南
Calypso vs PC-DMIS:三坐标测量软件脱机编程深度对比与实战选型策略 在精密制造领域,三坐标测量机(CMM)的脱机编程能力直接决定了检测效率与资源利用率。作为行业两大标杆,蔡司Calypso与海克斯康PC-DMIS在用户界面设计、编程逻辑、仿真验证等…...
HunyuanVideo-Foley成本效益分析:自建服务与使用商用API的对比
HunyuanVideo-Foley成本效益分析:自建服务与使用商用API的对比 1. 引言:音效生成的技术选择困境 在视频制作领域,高质量音效往往能决定作品的最终质感。HunyuanVideo-Foley作为先进的AI音效生成技术,为企业提供了两种主要使用路…...
Qwen3.5-2B图文理解教程:GIF动图逐帧理解+动态内容总结生成方法
Qwen3.5-2B图文理解教程:GIF动图逐帧理解动态内容总结生成方法 1. 引言 Qwen3.5-2B是一款轻量化多模态基础模型,属于Qwen3.5系列的小参数版本(20亿参数)。这款模型主打低功耗、低门槛部署,特别适配端侧和边缘设备&am…...
基于AI政策路径与通胀预期模型的美联储决策分析:鲍威尔观望信号引发加息预期归零
摘要:本文通过构建AI政策路径预测模型,结合通胀预期识别系统、能源价格传导算法与劳动力市场评估框架,对美联储在当前环境下的利率决策逻辑进行分析,重点解析“观望策略”背后的模型依据及市场加息预期快速回落的原因。一、AI政策…...
车载Java OTA升级崩溃率从18.7%降至0.3%:基于Delta Patch + 类隔离热修复的4步标准化流程
第一章:车载Java OTA升级崩溃率从18.7%降至0.3%:基于Delta Patch 类隔离热修复的4步标准化流程在车载嵌入式Java环境(JVM 11,ART兼容层)中,OTA升级引发的ClassCastException与NoClassDefFoundError曾导致高…...
5分钟彻底告别风扇噪音!FanControl终极静音配置完全指南
5分钟彻底告别风扇噪音!FanControl终极静音配置完全指南 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/…...
深入解析STM32 map文件:从编译到内存优化的关键步骤
1. 为什么STM32开发者必须掌握map文件分析 第一次接触STM32的map文件时,我和大多数新手一样感到一头雾水。这个由编译器自动生成的文本文件,乍看就像天书般难以理解。直到有次项目遇到内存不足的紧急情况,我才真正体会到map文件的价值——它不…...
iarduino_KB矩阵键盘库:硬件感知型Arduino按键驱动方案
1. 项目概述iarduino_KB是由俄罗斯嵌入式开发团队 iArduino.ru 面向 Arduino IDE 推出的专用矩阵键盘驱动库。该库并非通用型扫描抽象层,而是针对其自研四款物理形态与电气特性高度定制化的柔性/机械式矩阵键盘模块进行深度适配的固件级解决方案。其核心价值在于将底…...
