4.1 链式栈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博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/65117.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CCF HPC China2023|澎峰科技:使能先进计算,赋能行业应用

CCF HPC China2023圆满落幕&#xff01; 桂秋八月&#xff0c;为期三天的中国高性能计算领域最高规格盛会——2023CCF全球高性能计算学术年会&#xff08;HPC China&#xff09;在青岛红岛国际展览中心圆满落幕。行业超算大咖、顶级学界精英、先锋企业领袖参会者齐聚山东青岛&a…

联邦学习FedAvg-基于去中心化数据的深度网络高效通信学习

随着计算机算力的提升&#xff0c;机器学习作为海量数据的分析处理技术&#xff0c;已经广泛服务于人类社会。 然而&#xff0c;机器学习技术的发展过程中面临两大挑战&#xff1a;一是数据安全难以得到保障&#xff0c;隐私泄露问题亟待解决&#xff1b;二是网络安全隔离和行业…

uniapp 配置网络请求并使用请求轮播图

由于平台的限制&#xff0c;小程序项目中不支持 axios&#xff0c;而且原生的 wx.request() API 功能较为简单&#xff0c;不支持拦截器等全局定制的功能。因此&#xff0c;建议在 uni-app 项目中使用 escook/request-miniprogram 第三方包发起网络数据请求。 官方文档&#xf…

【C++入门】命名空间、缺省参数、函数重载、引用、内联函数

​&#x1f47b;内容专栏&#xff1a; C/C编程 &#x1f428;本文概括&#xff1a; C入门学习必备语法 &#x1f43c;本文作者&#xff1a; 阿四啊 &#x1f438;发布时间&#xff1a;2023.9.3 前言 C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加…

大数据-玩转数据-Flink窗口函数

一、Flink窗口函数 前面指定了窗口的分配器, 接着我们需要来指定如何计算, 这事由window function来负责. 一旦窗口关闭, window function 去计算处理窗口中的每个元素. window function 可以是ReduceFunction,AggregateFunction,or ProcessWindowFunction中的任意一种. Reduc…

打包个七夕exe玩玩

前段时间七夕 当别的哥们都在酒店不要不要的时候 身为程序员的我 还在单位群收到收到 正好后来看到大佬些的这个 https://www.52pojie.cn/thread-1823963-1-1.html 这个贱 我必须要犯&#xff0c;可是我也不能直接给他装个python吧 多麻烦 就这几个弹窗 好low 加上bgm 再打包成…

Nexus仓库介绍以及maven deploy配置

一 、Nexus仓库介绍 首先介绍一下Nexus的四个仓库的结构&#xff1a; maven-central 代理仓库&#xff0c;代理了maven的中央仓库&#xff1a;https://repo1.maven.org/maven2/&#xff1b; maven-public 仓库组&#xff0c;另外三个仓库都归属于这个组&#xff0c;所以我们的…

贝叶斯神经网络 - 捕捉现实世界的不确定性

贝叶斯神经网络 - 捕捉现实世界的不确定性 Bayesian Neural Networks 生活本质上是不确定性和概率性的&#xff0c;贝叶斯神经网络 (BNN) 旨在捕获和量化这种不确定性 在许多现实世界的应用中&#xff0c;仅仅做出预测是不够的&#xff1b;您还想知道您对该预测的信心有多大。例…

第2章 Linux多进程开发 2.18 内存映射

内存映射&#xff1a;可以进行进程间的通信 1.如果对mmap的返回值(ptr)做操作(ptr), munmap是否能够成功? void * ptr mmap(…); ptr; 可以对其进行操作 munmap(ptr, len); // 错误,要保存地址 2.如果open时O_RDONLY, mmap时prot参数指定PROT_READ | PROT_WRITE会怎样? 错…

二进制安全虚拟机Protostar靶场 安装,基础知识讲解,破解STACK ZERO

简介 pwn是ctf比赛的方向之一&#xff0c;也是门槛最高的&#xff0c;学pwn前需要很多知识&#xff0c;这里建议先去在某宝上买一本汇编语言第四版&#xff0c;看完之后学一下python和c语言&#xff0c;python推荐看油管FreeCodeCamp的教程&#xff0c;c语言也是 pwn题目大部…

SpringBoot 使用MyBatis分页插件实现分页功能

SpringBoot 使用MyBatis分页插件实现分页功能 1、集成pagehelper2、配置pagehelper3、编写代码4、分页效果 案例地址&#xff1a; https://gitee.com/vinci99/paging-pagehelper-demo/tree/master 1、集成pagehelper <!-- 集成pagehelper --> <dependency><gr…

“亚马逊云科技创业加速器”首期聚焦AI,促进入营企业业务发展

生成式AI技术飞速发展&#xff0c;颠覆着人们的生活&#xff0c;正在掀起新一轮的科技革命。在生成式AI的浪潮中&#xff0c;亚马逊云科技旨在为中国的优秀初创企业提供全方位支持&#xff0c;助其抢占先机。 在6月底举办的亚马逊云科技中国峰会上&#xff0c;亚马逊云科技联合…

6. series对象及DataFrame对象知识总结

【目录】 文章目录 6. series对象及DataFrame对象知识总结1. 导入pandas库2. pd.Series创建Series对象2.1 data 列表2.2 data 字典 3. s1.index获取索引4. s1.value获取值5. pd.DataFrame()-创建DataFrame 对象5.1 data 列表5.2 data 嵌套列表5.3 data 字典 6. df[列索引]…

java对象创建的过程

1、检查指令的参数是否能在常量池中定位到一个类的符号引用 2、检查此符号引用代表的类是否已被加载、解析和初始化过。如果没有&#xff0c;就先执行相应的类加载过程 3、类加载检查通过后&#xff0c;接下来虚拟机将为新生对象分配内存。 4、内存分配完成之后&#xff0c;…

一句话画出动漫效果

链接&#xff1a; AI Comic Factory - a Hugging Face Space by jbilcke-hfDiscover amazing ML apps made by the communityhttps://huggingface.co/spaces/jbilcke-hf/ai-comic-factory 选择类型&#xff1a; Japanese 输入提示词&#xff1a; beauty and school love st…

12、监测数据采集物联网应用开发步骤(9.1)

监测数据采集物联网应用开发步骤(8.2) TCP/IP Server开发 在com.zxy.common.Com_Para.py中添加如下内容 #锁机制 lock threading.Lock() #本机服务端端口已被连接客户端socket list dServThreadList {} #作为服务端接收数据拦截器 ServerREFLECT_IN_CLASS "com.plug…

设计模式-装饰模式

文章目录 一、简介二、基本概念三、装饰模式的结构和实现类图解析&#xff1a;装饰器的实现方式继承实现&#xff1a;组合实现&#xff1a;继承和组合对比 四、装饰模式的应用场景五、与其他模式的关系六、总结 一、简介 装饰模式是一种结构型设计模式&#xff0c;它允许动态地…

msvcp120.dll丢失的解决方法?全面解决方法推荐

msvcp120.dll是Windows操作系统中的一个关键组件&#xff0c;如果丢失或损坏&#xff0c;可能会导致系统崩溃或无法正常运行。本文将介绍三种解决msvcp120.dll丢失问题的方法。 随着计算机应用的广泛普及&#xff0c;越来越多的人开始遇到各种电脑问题。其中&#xff0c;msvcp…

FPGA原理与结构——FIFO IP核的使用与测试

一、前言 本文介绍FIFO Generator v13.2 IP核的具体使用与例化&#xff0c;在学习一个IP核的使用之前&#xff0c;首先需要对于IP核的具体参数和原理有一个基本的了解&#xff0c;具体可以参考&#xff1a; FPGA原理与结构——FIFO IP核原理学习https://blog.csdn.net/apple_5…

算法通关村第十二关——字符串反转问题解析

前言 字符串反转是关于字符串算法里的重要问题&#xff0c;虽然不是太难&#xff0c;但需要考虑到一些边界问题。本篇文章就对几道字符串反转题目进行分析。 1.反转字符串 力扣344题&#xff0c;编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数…