顺序栈和链式栈(C++实现)

news/2024/7/8 13:19:15/文章来源:https://blog.csdn.net/st66688/article/details/127056248

数据结构(面向对象方法与C++语言描述)(第2版)顺序栈和链式栈内容整理

栈(stack)可定义为只允许在表的末端进行插入和删除的线性表。允许插入和删除的一端叫做栈顶(top),而不允许插入和删除的另一端叫做栈底(bottom)。当栈中没有任何元素时,则成为空栈。

设给定栈 S =(a1,a2,……,an),则称最后加入栈中的元素为栈顶。栈中按a1,a2,……,an的顺序进栈。而退栈的顺序反过来,an先退出,然后an-1才能退出,最后退出a1。换句话说,后进者先出。因此,栈又叫座后进先出(LIFO,Last In First Out)的线性表。

在这里插入图片描述

栈的抽象数据类型有两种典型的存储表示:基于数组的存储表示和基于链表的存储表示。基于数组的存储表示实现的栈称为顺序栈,基于链表的存储表示实现的称为链式栈。

顺序栈

顺序栈可以采用顺序表作为其存储表示,为此,可以再顺序栈中的声明中用顺序表定义它的存储空间。为简化问题起见,使用一维数组作为栈的存储空间。存放栈元素的数组的头指针为* elements,该数组的最大允许存放元素个数为 maxSize,当前栈顶位置由数组下标指针 top 指示。如果栈不空时 elements[0]是栈中第一个元素。

链式栈

链式栈是线性表的链式存储表示。采用链式栈来表示一个栈,便于结点的插入与删除。在程序中同时使用多个栈的情况下,用链接表示不仅能够提高效率,还可以达到共享存储空间的目的。

代码实现

环境:vs2019
头文件:Stack.h
源文件:main.cpp

Stack.h代码:

#pragma onceconst int maxSize = 50;template<typename T>
class Stack {												//栈的类定义
public:Stack() {};												//构造函数virtual void Push(const T& x) = 0;						//新元素x进栈virtual bool Pop(T& x) = 0;								//栈顶元素出栈,由x返回virtual bool getTop(T& x) const = 0;					//读取栈顶元素,由x返回virtual bool IsEmpty() const = 0;						//判断栈空否virtual bool IsFull() const = 0;						//判断栈满否virtual int getSize() const = 0;						//计算栈中元素个数
};

SeqStack.hpp代码:

#pragma once#include <iostream>
#include <cassert>
#include "Stack.h"using std::cerr;
using std::cout;
using std::endl;
using std::ostream;const int stackIncreament = 20;					//栈溢出时扩展空间增量template<typename T>
class SeqStack :public Stack<T> {				//顺序栈的类定义
public:SeqStack(int sz = 50);						//建立一个空栈~SeqStack() { delete[] elements; }			//析构函数void Push(const T& x);						//如果IsFull(),则溢出处理;否则把x插入到栈的栈顶。bool Pop(T& x);								//如果IsEmpty(),则不执行退栈,返回false;否则退掉位于栈顶的元素,返回true;//退出的元素值通过引用型参数x返回bool getTop(T& x) const;					//如果IsEmpty(),则返回false;否则返回true,并通过引用型参数x得到栈顶元素的值。bool IsEmpty() const { return (top == -1) ? true : false; }//如果栈中元素个数等于0,则返回true,否则返回false。bool IsFull() const { return (top == maxSize - 1) ? true : false; }//如果栈中元素个数等于maxSize则返回true,否则返回false。int getSize() const { return top + 1; }		//函数返回栈中元素个数。void MakeEmpty() { top = -1; }				//清空栈中内容template<typename T>friend ostream& operator<<(ostream& os, SeqStack<T>& s);//输出栈中元素的重载操作<<
private:T* elements;								//存放栈中元素的栈数组int top;									//栈顶指针int maxSize;								//栈最大可容纳元素个数void overflowProcess();						//栈的溢出处理
};template<typename T>
inline SeqStack<T>::SeqStack(int sz):top(-1), maxSize(sz)
{//建立一个最大尺寸为sz的空栈,若分配不成功则错误处理。elements = new T[maxSize];					//创建栈的数组空间assert(elements != nullptr);					//断言:动态存储分配成功与否
}template<typename T>
inline void SeqStack<T>::Push(const T& x)
{//公共函数:若栈不满,则将元素x插入到该栈的栈顶,否则溢出处理。if (IsFull() == true) overflowProcess();	//栈满则溢出处理elements[++top] = x;						//栈顶指针先加1,在进栈
}template<typename T>
inline bool SeqStack<T>::Pop(T& x)
{//公共函数:若栈不空则函数返回该栈栈顶元素的值,然后栈顶指针退1。if (IsEmpty() == true) return false;		//判栈空否,若栈空则函数返回x = elements[top--];						//栈顶指针退1return true;								//退栈成功
}template<typename T>
inline bool SeqStack<T>::getTop(T& x) const
{//公共函数:若栈不空则函数返回该栈栈顶元素的地址。if (IsEmpty() == true) return false;		//判栈空否,若栈空则函数返回x = elements[top];							//返回栈顶元素的值return true;
}template<typename T>
inline void SeqStack<T>::overflowProcess()
{//私有函数:扩充栈的存储空间。T* newArray = new T[maxSize + stackIncreament];if (newArray == nullptr) { cerr << "存储分配失败!" << endl; exit(1); }for (int i = 0; i <= top; i++) newArray[i] = elements[i];maxSize = maxSize + stackIncreament;delete[] elements;elements = newArray;
}template<typename T>
ostream& operator<<(ostream& os, SeqStack<T>& s)
{//输出栈中元素的重载操作<<。os << "top = " << s.top << endl;			//输出栈顶元素for (int i = 0; i <= s.top; i++)			//逐个输出栈中元素os << i << ":" << s.elements[i] << endl;return os;
}

LinkedList.hpp代码:

#pragma once#include <iostream>template<typename T>
struct LinkNode {											//链表结点的定义T data;													//数据域LinkNode<T>* link;										//链指针域LinkNode(LinkNode<T>* ptr = nullptr) { link = ptr; }	//仅初始化指针成员的构造函数LinkNode(const T& item, LinkNode<T>* ptr = nullptr)		//初始化数据与指针成员的构造函数{data = item;link = ptr;}
};template<typename T>
class List {
public:List() { first = new LinkNode<T>; }						//构造函数List(const T& x) { first = new LinkNode<T>(x); }		//构造函数List(List<T>& L);										//拷贝构造函数~List() { makeEmpty(); }								//析构函数void makeEmpty();										//将链表置为空表int Length()const;										//计算链表的长度LinkNode<T>* getHead()const { return first; }			//返回附加头结点地址LinkNode<T>* Search(T x);								//搜索含数据x的元素LinkNode<T>* Locate(int i)const;						//搜索第i个元素的地址bool getData(int i, T& x)const;							//取出第i个元素的地址void setData(int i, T& x);								//用x修改第i个元素的值bool Insert(int i, T& x);								//在第i个元素后插入xbool Remove(int i, T& x);								//删除第i个元素,x返回该元素的值bool IsEmpty()const										//判表空否?空则返回true{return first->link == nullptr ? true : false;}bool IsFull()const { return false; }					//判表满否?不满则返回falsevoid Sort();											//排序void input();											//输入void output();											//输出List<T>& operator=(List<T>& L);							//重载运算符=void inputFront(T endTag);								//前插法建立单链表void inputRear(T endTag);								//后插法建立单链表
protected:LinkNode<T>* first;										//链表的头指针
};template<typename T>
inline List<T>::List(List<T>& L)
{//拷贝构造函数T value;LinkNode<T>* srcptr = L.getHead();						//被赋值表的附加头结点地址LinkNode<T>* destptr = first = new LinkNode<T>;while (srcptr->link != nullptr)							//逐个结点复制{value = srcptr->link->data;destptr->link = new LinkNode<T>(value);destptr = destptr->link;srcptr = srcptr->link;}destptr->link = nullptr;
}template<typename T>
inline void List<T>::makeEmpty()
{//将链表置位空表LinkNode<T>* q;while (first->link != nullptr)							//当链不空时,删去链中所有结点{q = first->link;first->link = q->link;								//保存被删结点,从链上摘下该节点delete q;											//删除(仅保留一个表头节点)}
}template<typename T>
inline int List<T>::Length() const
{//计算带附加头结点的单链表的长度LinkNode<T>* p = first->link;int count = 0;while (p != nullptr)									//循链扫描,寻找链尾{p = p->link;count++;}return count;
}template<typename T>
inline LinkNode<T>* List<T>::Search(T x)
{//在表中搜索含数据x的节点,搜索成功时函数返回该节点地址;否则返回NULL值。LinkNode<T>* current = first->link;while (current != nullptr){if (current->data == x) break;						//循链找含x结点else current = current->link;}return current;
}template<typename T>
inline LinkNode<T>* List<T>::Locate(int i) const
{//定位函数。返回表中第i个元素的地址。若i<0或i超过表中结点个数,则返回NULL。if (i < 0) return nullptr;								//i不合理LinkNode<T>* current = first;int k = 0;while (current != nullptr && k < i)						//循链找第i个结点{current = current->link;k++;}return current;											//返回第i个结点地址,若返回NULL,表示i值太大
}template<typename T>
inline bool List<T>::getData(int i, T& x) const
{//取出链表中第i个元素的值。if (i <= 0) return false;								//i值太小LinkNode<T>* current = Locate(i);if (current == nullptr) return false;					//i值太大else{x = current->data;return true;}
}template<typename T>
inline void List<T>::setData(int i, T& x)
{//给链表中的第i个元素赋值x。if (i <= 0) return;										//i值太小LinkNode<T>* current = Locate(i);if (current == nullptr) return;							//i值太大else current->data = x;
}template<typename T>
inline bool List<T>::Insert(int i, T& x)
{//将新元素x插入在链表中第i个结点之后。LinkNode<T>* current = Locate(i);if (current == nullptr) return false;					//插入不成功LinkNode<T>* newNode = new LinkNode<T>(x);if (newNode == nullptr){std::cerr << "存储分配错误!" << std::endl;exit(1);}newNode->link = current->link;current->link = newNode;return true;											//插入成功
}template<typename T>
inline bool List<T>::Remove(int i, T& x)
{//将链表中的第i个元素扇区,通过引用型参数x返回该元素的值。LinkNode<T>* current = Locate(i - 1);if (current == nullptr || current->link == nullptr)	return false;//删除不成功LinkNode<T>* del = current->link;						//重新拉链,将被删结点从链中摘下current->link = del->link;x = del->data;delete del;												//取出被删结点中的数据值return true;
}template<typename T>
inline void List<T>::Sort()
{
}template<typename T>
inline void List<T>::input()
{
}template<typename T>
inline void List<T>::output()
{//单链表的输出函数:将单链表中所有数据按逻辑顺序输出到屏幕上。std::cout << "链表中的元素为:" << std::endl;LinkNode<T>* current = first->link;while (current != nullptr){std::cout << current->data << " ";current = current->link;}std::cout << std::endl;
}template<typename T>
inline List<T>& List<T>::operator=(List<T>& L)
{//重载函数:赋值操作,形式如 A = B,其中 A 是调用此操作的List对象,B 是参数表中的//引用型参数L结合的实参。makeEmpty();T value;LinkNode<T>* srcptr = L.getHead();						//被复制表的附加头结点地址LinkNode<T>* destptr = first = new LinkNode<T>;while (srcptr->link != nullptr)							//逐个结点复制{value = srcptr->link->data;destptr->link = new LinkNode<T>(value);destptr = destptr->link;srcptr = srcptr->link;}destptr->link = nullptr;return *this;											//返回操作对象地址
}template<typename T>
inline void List<T>::inputFront(T endTag)
{//endTag是约定的输入序列结束的标志。如果输入序列是正整数,endTag可以是0或负数;//如果输入序列是字符,endTag可以是字符集中不会出现的字符,如"\0"。LinkNode<T>* newNode;T val;makeEmpty();std::cin >> val;while (val != endTag){newNode = new LinkNode<T>(val);						//创建新结点if (newNode == nullptr){std::cerr << "存储分配错误!" << std::endl;exit(1);}newNode->link = first->link;first->link = newNode;								//插入到表最前端std::cin >> val;}
}template<typename T>
inline void List<T>::inputRear(T endTag)
{//endTag是约定的输入序列结束的标志LinkNode<T>* newNode, * last;T val;makeEmpty();std::cin >> val;last = first;while (val != endTag)									//last指向表尾{newNode = new LinkNode<T>(val);if (newNode == nullptr){std::cerr << "存储分配错误!" << std::endl;exit(1);}last->link = newNode;last = newNode;std::cin >> val;									//插入到表末端}last->link = nullptr;									//表首位,这一句实际可省略
}

LinkedStack.hpp代码:

#pragma once#include <iostream>
#include "Stack.h"
#include "LinkedList.hpp"using std::ostream;
using std::cout;
using std::endl;template<typename T>
class LinkedStack :public Stack<T> {				//链式栈类定义
public:LinkedStack() :top(nullptr) { }					//构造函数,置空栈~LinkedStack() { makeEmpty(); }					//析构函数				void Push(const T& x);							//进栈bool Pop(T& x);									//出栈bool getTop(T& x) const;						//读取栈顶元素bool IsEmpty() const { return (top == nullptr) ? true : false; }bool IsFull() const { return false; }int getSize() const;							//求栈的元素个数void makeEmpty();								//清空栈的内容template<typename T>friend ostream& operator<<(ostream& os, LinkedStack<T>& s);//输出栈中元素的重载操作<<
private:LinkNode<T>* top;								//栈顶指针,即链头指针
};template<typename T>
inline void LinkedStack<T>::Push(const T& x)
{//将元素值x插入到链式栈的栈顶,即链头。top = new LinkNode<T>(x, top);					//创建新的含x结点assert(top != nullptr);							//创建新结点失败退出
}template<typename T>
inline bool LinkedStack<T>::Pop(T& x)
{//删除栈顶结点,返回被删栈顶元素的值。if (IsEmpty() == true) return false;			//若栈空则不退栈,返回LinkNode<T>* p = top;							//否则暂存栈顶元素top = top->link;								//栈顶指针退到新的栈顶位置x = p->data;delete p;										//释放结点,返回退出元素的值return false;
}template<typename T>
inline bool LinkedStack<T>::getTop(T& x) const
{//返回栈顶元素的值if (IsEmpty() == true) return false;			//若栈空则返回falsex = top->data;									//栈不空则返回栈顶元素的值return true;
}template<typename T>
inline int LinkedStack<T>::getSize() const
{LinkNode<T>* p = top;int k = 0;while (p != nullptr){p = p->link;k++;}return k;
}template<typename T>
inline void LinkedStack<T>::makeEmpty()
{//逐次删去链式栈中的元素直至栈顶指针为空。LinkNode<T>* p;while (top != nullptr)							//逐个结点释放{p = top;top = top->link;delete p;}
}template<typename T>
ostream& operator<<(ostream& os, LinkedStack<T>& s)
{//输出栈中元素的重载操作<<os << "栈中元素个数 = " << s.getSize() << endl;	//输出栈中元素个数LinkNode<T>* p = s.top;int i = 0;while (p != nullptr)							//逐个输出栈中元素的值{os << ++i << ":" << p->data << endl;p = p->link;}return os;
}

main.cpp代码:

#include "SeqStack.hpp"
#include "LinkedStack.hpp"int main()
{SeqStack<int> s1;cout << "栈s1的元素个数为:" << s1.getSize() << endl;s1.Push(10);s1.Push(20);s1.Push(30);cout << "栈s1的元素个数为:" << s1.getSize() << endl;cout << s1;LinkedStack<int> s2;cout << "栈s2的元素个数为:" << s2.getSize() << endl;s2.Push(10);s2.Push(20);s2.Push(30);cout << "栈s2的元素个数为:" << s2.getSize() << endl;cout << s2;return 0;
}

控制台界面:
在这里插入图片描述

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

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

相关文章

学习:网络基础知识 HTTP协议之请求报文

HTTP协议 和 安全版 HTTPS协议 HTTP(Hyper Text Transfer Protocol)超文本传输协议 HTTP协议 是基于TCP协议 默认端口是80 功能:用来规定客户端和服务端的数据传输格式 特点:基于请求与响应模式的、无状态、无连接的应用层协议 示例:粉色部分是请求 紫色是响应部分 HTTP请…

Pro09丨高频波动率RSJ与成交量因子迭代升级

量化策略开发&#xff0c;高质量社群&#xff0c;交易思路分享等相关内容 『正文』 ˇ 大家好&#xff0c;今天我们分享Pro系列第9篇量化策略及内容说明。 在2021年7月中&#xff0c;某开源平台发布一个研报策略复现文章&#xff0c;而后大家象征性的积极讨论了一番&#xf…

大裁员时代,我们究竟该如何提升自己?

我以为进大厂可以逃过 35 岁的坎儿&#xff0c;结果还没到 35 呢就遇上了大裁员。。。被裁的那一个月&#xff0c;我拿着公司给的 2N 在家躺了大半个月&#xff0c;刚开始是不甘&#xff0c;到后面每个月一万多的房贷催着我不得不重新审视自己&#xff0c;随后踏上了海投之路。…

贤鱼的刷题日常--P2671 [NOIP2015 普及组] 求和

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;学会求和题目 ✅创作者&#xff1a;贤鱼 &#x1f389;个人主页&#xff1a;贤鱼的个人主页 &#x1f525;专栏系列&#xff1a;c 求和题目[NOIP2015 普及组] 求和题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例…

电脑屏幕监控,员工行为监控,上网行为监控解决方案

本文镜像&#xff1a;https://linkpi.cn/archives/1612 本文链接&#xff1a;https://blog.csdn.net/weixin_45326556/article/details/127050574 电脑屏幕监控,员工行为监控,上网行为监控解决方案1. 背景2. 设备清单3. 设备连接示意图3.1 灵派编码器 USB摄像头方式3.2 灵派编…

C++运算符重载

运算符重载引入一.运算符重载是什么二.运算符重载的格式三.部分运算符重载的实现3.1 简单‘ ’ ‘ - ’ ‘ * ’运算符重载3.2 ,- - 运算符3.3 运算符3.4 <<&#xff0c;>>运算符四.运算符重载注意事项五.运算符重载的限制六.MyString的简单实现引入 对于基本类型…

java中的IO流

IO流1、File类1.1 获取文件或目录信息1.2 操作文件1.3 操作目录1.4 案例&#xff1a;递归列出目录的下一级1.5 案例&#xff1a;递归列出目录下的所有Java源文件2、IO流的分类和设计2.1 输出纯文本数据2.2 读取纯文本数据2.3 按行读取2.4 复制文件基本版2.5 复制文件提升效率版…

硬件基础:电路基础知识

电路的研究方式&#xff1a;从电路模型出发&#xff0c;研究电路基本理论、分析方法以及工程技术中典型类电路的特点和规律。 电路的四类知识 基础知识 电路模型&#xff0c;电路基本物理量&#xff0c;电路基本元件&#xff0c;基尔霍夫定律&#xff0c;磁路的基础知识。。。工…

CloudCompare——软件汉化

目录1.效果预览2.软件实现1.效果预览 如图所示&#xff0c;软件界面上显示内容翻译成中文。 2.软件实现 1、下载最新版本的CloudCompare&#xff0c;如图所示&#xff0c;下载箭头所指的任意一个版本即可。 官网下载链接&#xff1a;http://www.danielgm.net/cc/release/ …

数据分析:单元4 Matplotlib库入门

Matplotlib 可能是 Python 2D-绘图领域使用最广泛的套件。它能让使用者很轻松地将数据图形化&#xff0c;并且提供多样化的输出格式。在这里我将介绍一下它的相关知识&#xff0c;你可以在这里快速学会如何用它画出好看的数据图像&#xff0c;如果你想学习到更多的知识&#xf…

跟 HTML 说hello

目 录 ​1.HTML的骨架标签 2.迎接自己的第一个HTML网页 聊起前端,最最最基础的应该就是HTML语言了哈!首先, HTML 指的是超文本标记语言 (Hyper Text Markup Language)是用来描述网页的一种语言 。超文本的含义就在于它可以加入图片、声音、动画、多媒体等内容&#xff08…

8、React路由

1、介绍 SPA概念&#xff1a;单页Web应用&#xff08;single page web application&#xff09;&#xff0c;就是只有一张Web页面的应用&#xff0c;由一个主页面和多个页面片段组成&#xff0c;由JS控制页面片段的展示与否。整个页面不会刷新&#xff0c;只会做局部页面的更新…

第三章、运输层(重点知识梳理)

3.1概述和运输层服务 3.1.1运输层概述 运输层协议是为运行在不同主机上的应用进程之间提供逻辑通信 传输协议运行在端系统 发送方&#xff1a;将应用层的报文分成报文段&#xff0c;然后传递给网络层接收方&#xff1a;将报文段重组成报文&#xff0c;然后传递给应用层有多个传…

前端设计走查平台实践(前端篇)

项目背景 随着前端业务的不断发展&#xff0c;前端对设计稿的还原程度也成为了影响用户对产品体验的一个关键指标&#xff0c;作为最靠近用户侧的研发&#xff0c;前端工程师通常需要和设计师同学通力配合来提升用户体验。其中&#xff0c;设计走查是设计同学最常见的测试前端同…

以赛促产 以赛引才 |第六届世界智能大会·中国华录杯数据湖算法大赛正式启动

6月24日&#xff0c;由天津市委网信办、天津市工业和信息化局、天津市津南区人民政府、中国华录集团有限公司主办&#xff0c;北京易华录信息技术股份有限公司承办的“第六届世界智能大会中国华录杯数据湖算法大赛”正式启动。 赛事发布 本次大赛以数据“收、存、治、用、易”…

【Unity Shader】纹理实践2.0:基本属性封装和滤波模式

关于理论知识 【技术美术图形部分】纹理基础1.0-纹理管线_flashinggg的博客-CSDN博客 上篇是总结了纹理映射一整个的流程&#xff0c;其中2.3纹理采样中提到了需要进行两块设置&#xff1a; 设置封装模式——Wrap Mode&#xff0c;介绍了封装模式都有哪些设置过滤模式——Fi…

Slam:求解外参即图优化建模过程

前言 我学习 Slam 14讲 的时候感觉图优化那一段好难懂&#xff01;经过我的查询&#xff0c;终于有了大致的了解&#xff0c;记录并分享。终于明白slam的图优化了&#xff01;&#xff08;图优化就是空壳子&#xff09;。一开始 g20, 边&#xff0c;节点什么的晕死了&#xff…

【多图像展示】仿照StyleGAN1层次化展示不同大小图片

代码出处 &#xff1a; https://github.com/NVlabs/stylegan/blob/master/generate_figures.py 本文代码 参数含义 cx0 , 图片展示的起始x坐标cy0 , 图片展示的起始y坐标cw512 原始图片的宽度&#xff0c;展示图片的最大宽度&#xff0c;后续以2的阶乘缩小ch1024 原始单张图…

java基本微信小程序的汉服租赁平台 uniapp 小程序

随着因特网技术的迅速发展,各种各样的网站已经深入到日常生活的各个角落。特别是在汉代文化的影响之下,租赁汉服的人越来越多,也越来越广,全国各地都有租赁者。为了服务于广大汉服爱好者且迎合汉服市场的需求,开发一个基于微信小程序的汉服租赁平台也是很有必要的。 环境需要 1…

【算法面试必刷Java版十六】删除有序链表中重复的元素2

盲目刷题&#xff0c;浪费大量时间&#xff0c;博主这里推荐一个面试必刷算法题库&#xff0c;刷完足够面试了。传送门&#xff1a;牛客网面试必刷TOP101 &#x1f3c4;&#x1f3fb;作者简介&#xff1a;CSDN博客专家&#xff0c;华为云云享专家&#xff0c;阿里云专家博主&am…