数据结构 - 栈

news/2024/10/14 0:17:29

栈一种常见的特殊线性数据结构,其特殊之处在于其操作顺序,下面会详细介绍,也正因为其特性,因此栈可以轻松解决表达式求值、括号匹配、递归算法、回溯算法等等问题。

01、定义

栈的特殊性表现为操作受限,其一只允许在栈的一端进行元素插入和删除运算,其二栈的运算操作遵循后进先出(Last In First Out,简称LIFO)的原则。

入栈:当把元素插入到栈,这一行为叫做入栈,也称进栈或压栈;

出栈:当把元素从栈中移除,这一行为叫做出栈,也称退栈;

栈顶:允许元素进行插入和删除操作的一端称为栈顶;

栈底:与栈顶对应的另一个端称为栈底,并且不允许进行元素操作;

空栈:当栈中没有元素时叫做空栈。

满栈:当栈是有限容量,并且容量已用完,则称为满栈。

栈容量:当栈是有限容量,栈容量表示栈可以容纳的最大元素数量。

栈大小:表示当前栈中的元素数量。

02、分类

栈是逻辑结构,因此以存储方式的不同可以分为顺序栈和链栈。

顺序栈就是使用连续的地址空间存储所有栈元素,通常采用数组实现,因此导致栈的大小是固定的,不易扩扩容,容易浪费空间同时还要注意元素溢出等问题。

链栈顾名思义就是采用链式方式存储,通常采用单向链表实现,因此链栈可以无限扩容,按需使用,内存利用高效,同时也不存在满栈的情况。

03、实现(顺序栈)

我们借助数组来实现顺序栈,其核心思想是把数组的起始位置作为栈底,把数组尾方向当作栈顶。

我们知道数组对插入、删除元素是不友好的,因为涉及到已存在元素移动的问题,但是如果直接在数组尾端插入、删除元素还是很方便的,因为不涉及元素移动问题,我们正是利用这一特点,把数组起始位置做为栈底,而插入、删除方便的数组尾端作为栈顶。

下面我们将一步一步实现一个泛型顺序栈。

1、ADT定义

我们首先来定义顺序栈的ADT。

ADT Stack{

数据对象:D 是一个非空的元素集合,D = {a1, a2, ..., an},其中 ai 表示栈中的第i个元素,n是栈的长度。数据关系:D中的元素通过它们的索引(位置)进行组织,索引是从0到n-1的整数,并且遵循元素只能在栈顶操作,元素后进先出的原则。基本操作:[Init(n) :初始化一个指定容量的空栈。Capacity:返回栈容量。Length:返回栈长度。Top:返回栈顶元素,当为空栈则报异常。IsEmpty():返回是否为空栈。IsFull():返回是否为满栈。Push():入栈即添加元素,当为满栈则报异常。Pop():出栈即返回栈顶元素并把其从栈中移除,当为空栈则报异常。

]

}

定义好栈ADT,下面我们就可以开始自己实现的栈。

2、初始化Init

初始化结构主要做几件事。

  • 初始化栈的容量;

  • 初始化存放栈元素数组;

  • 初始化栈顶索引;

具体实现代码如下:

//存放栈元素
private T[] _array;
//栈容量
private int _capacity;
//栈顶索引,为-1表示空栈
private int _top;
//初始化栈为指定容量
public MyselfArrayStack<T> Init(int capacity)
{//初始化栈容量为capacity_capacity = capacity;//初始化指定长度数组用于存放栈元素_array = new T[_capacity];//初始化为空栈_top = -1;//返回栈return this;
}

3、获取栈容量 Capacity

这个比较简单直接把栈容量私有字段返回即可。

//栈容量
public int Capacity
{get{return _capacity;}
}

4、获取栈长度 Length

因为栈顶索引表示数组下标,因此可以通过栈顶索引加1转为栈长度,同时因为我们定义了空栈是栈顶索引为-1,因此此时栈长等于[-1+1]为0,所以栈长度即为[栈顶索引+1]。

//栈长度
public int Length
{get{//栈长度等于栈顶元素加1return _top + 1;}
}

5、获取栈顶元素 Top

获取栈顶元素可以通过栈顶索引私有字段从数组中直接获取,同时要注意判断栈是否为空栈,如果为空栈则报异常。具体代码如下:

//获取栈顶元素
public T Top
{get{if (IsEmpty()){//空栈,不可以进行获取栈顶元素操作throw new InvalidOperationException("空栈");}return _array[_top];}
}

6、获取是否空栈 IsEmpty

是否空栈只需判断栈顶索引是否为小于0即可。

//是否空栈
public bool IsEmpty()
{//栈顶索引小于0表示空栈return _top < 0;
}

7、获取是否满栈 IsFull

是否满栈只需判断栈顶索引是否与栈容量减1相等,代码如下:

//是否满栈
public bool IsFull()
{//栈顶索引等于容量大小表示满栈return _top == _capacity - 1;
}

8、入栈 Push

入栈则是在把栈顶索引向数组后移动一位后,再把新元素赋值到栈顶索引所对应的元素上,同时还需要检查是否为满栈,如果是满栈则报错,具体实现代码如下:

//入栈
public void Push(T value)
{if (IsFull()){//栈顶索引大于等于容量大小减1,表明已经满栈,不可以进行入栈操作throw new InvalidOperationException("满栈");}//栈顶索引先向后移动1位,然后再存放栈顶元素_array[++_top] = value;
}

9、出栈 Pop

出栈则是首先取出栈顶元素后,然后把栈顶索引向数组前移动一位,最后返回取出的栈顶元素,同时还需要检查是否为空栈,如果是空栈则报错,具体实现代码如下:

//出栈
public T Pop()
{if (IsEmpty()){//栈顶索引小于1表示空栈,不可以进行出栈操作throw new InvalidOperationException("空栈");}//返回栈顶元素后,栈顶索引向前移动1位return _array[_top--];
}

04、实现(链栈)

我们借助链表来实现链栈,其核心思想是把链表尾节点作为栈底,把链表首元节点当作栈顶。

这是因为如果我们想拿到链表的尾节点需要变量整个链表才可以拿到,但是要想获取首元节点则可以通过头指针直接获取到(无头节点链表),因此对于链表尾节点来说操作时不友好的适合来做栈底,链表首元节点对操作友好适合做为栈顶。

下面我们将一步一步实现一个泛型链栈。

1、ADT定义

相对于顺序栈的ADT来说,链栈的ADT少了两个方法即获取栈容量和是否满栈,这也是链表特性带来的好处。

2、初始化Init

初始化结构主要初始化栈顶节点为空和栈长度为0,具体实现如下:

public class MyselfStackNode<T>
{//数据域public T Data;//指针域,即下一个节点public MyselfStackNode<T> Next;public MyselfStackNode(T data){Data = data;Next = null;}
}
public class MyselfStackLinkedList<T>
{//栈顶节点即首元节点private MyselfStackNode<T> _top;//栈长度private int _length;//初始化栈public MyselfStackLinkedList<T> Init(){//初始化栈顶节点为空_top = null;//初始化栈长度为0_length = 0;//返回栈return this;}
}

3、获取栈长度 Length

这个比较简单直接把栈长度私有字段返回即可。

//栈长度
public int Length
{get{return _length;}
}

4、获取栈顶元素 Top

获取栈顶元素可以通过栈顶节点直接获取,但是要注意判断栈是否为空栈,如果为空栈则报异常。具体代码如下:

//获取栈顶元素
public T Top
{get{if (IsEmpty()){//空栈,不可以进行获取栈顶元素操作throw new InvalidOperationException("空栈");}//返回首元节点数据域return _top.Data;}
}

5、获取是否空栈 IsEmpty

是否空栈只需判断栈顶节点是否为空即可。

//是否空栈
public bool IsEmpty()
{//栈顶节点为null表示空栈return _top == null;
}

6、入栈 Push

入栈则是首先创建一个新节点,然后把原栈顶节点赋值给新节点的指针域,最后把新节点变更为栈顶节点,同时栈长加1,具体实现代码如下:

//入栈
public void Push(T value)
{//创建新的栈顶节点var node = new MyselfStackNode<T>(value);//将老的栈顶节点赋值给新节点的指针域node.Next = _top;//把栈顶节点变更为新创建的节点_top = node;//栈长度加1_length++;
}

7、出栈 Pop

出栈则是首先取出栈顶节点对应的数据后,然后把栈顶节点指向原栈顶节点对应的下一个节点,同时栈长度减1,当然如果空栈则报错,具体实现代码如下:

//出栈
public T Pop()
{if (IsEmpty()){//空栈,不可以进行出栈操作throw new InvalidOperationException("空栈");}//获取栈顶节点数据var data = _top.Data;//把栈顶节点变更为原栈顶节点对应的下一个节点_top = _top.Next;//栈长度减1_length--;//返回栈顶数据return data;
}

:测试方法代码以及示例源码都已经上传至代码库,有兴趣的可以看看。https://gitee.com/hugogoos/Planner

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

《使用Gin框架构建分布式应用》阅读笔记:p20-p31

《用Gin框架构建分布式应用》学习第2天,p20-p31总结,总计12页。 一、技术总结 1.第一个gin程序 // main.go package mainimport "github.com/gin-gonic/gin"func main() {r := gin.Default()r.GET("/", func(c *gin.Context) {c.JSON(200, gin.H{"m…

hot100 review

56. 合并区间 https://leetcode.cn/problems/merge-intervals/description/?envType=study-plan-v2&envId=top-100-liked 该怎么排序区间 vector<vector>& intervals sort(intervals)即可 238. 除自身以外数组的乘积 https://leetcode.cn/problems/product-of-a…

inline、const、mutable、this、static

inline、const、mutable、this、static 在类定义中实现成员函数 incline成员函数末尾的 const(声明和实现中都要加上 const) 作用:告诉系统,这个成员函数不会修改该对象里任何成员变量的值等等,也就是说,这个成员函数不会修改类 Time的任何状态。===> 也叫做常量成员函…

吴恩达机器学习笔记(2-1到2-7)

吴恩达机器学习笔记(2-1到2-7) https://www.bilibili.com/video/BV164411b7dx?p=5 https://www.bilibili.com/video/BV164411b7dx?p=6 https://www.bilibili.com/video/BV164411b7dx?p=7 https://www.bilibili.com/video/BV164411b7dx?p=8 https://www.bilibili.com/vide…

网络安全问题

Linux:在配置Centos7时,刚开始yum不能使用,原因是它默认使用的是自带的yum源,但是这个yum源很不稳定 解决方法:将其换成国内源yum的配置文件在/etc/yum.repos.d/CentOS-Base.repo当中,我们将其切换成阿里云镜像使用这个语句:curl -o /etc/yum.repos.d/CentOS-Base.repo …

分布式事务之Seata的AT模型

在Seata的事务管理中有三个重要的角色:TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。 TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。 RM (Resource Manager) - 资源管理…

【蓝队】Sysmon识别检测宏病毒

原创 玄影实验室 权说安全前言 在不断变化的网络安全环境中,提前防范威胁是非常重要的。 本文将以 Microsoft Office 宏病毒钓鱼为例,介绍如何使用 Sysmon 来获取和分析 Windows 系统日志,揭示隐藏的恶意或异常活动,了解入侵者和恶意软件如何在网络上运行。 Sysmon Sysmon(…

vue2进阶篇:vue-router之命名路由

vue2进阶篇:vue-router之命名路由@目录10.6命名路由案例:将案例改为“命名路由”完整代码本人其他相关文章链接 10.6命名路由注意点1: 命名路由请使用name属性,替换掉path属性的作用,且name直接指定名称即可,而path必须指定3级目录(path=’/demo/test/welcome’)才行。…