线性结构之栈结构

news2024/7/4 22:40:42

        栈是一种只能从一端存取数据并且遵循“后进先出”原则的线性存储结构。这句话中体现了栈结构的三个特征——只能从一端存取数据,遵循“后进先出”的原则和线性存储结构。因此如果我们要实现一个栈结构的数据结构,就必须要满足这三点要求。提到线性结构,最容易想到的就是数组,因此栈结构的底层可以通过数组来存储数据。那么如何实现只能从一段存取数据和“后进先出”的原则呢?这里要知道,后面的这两个条件都和存取数据有关,而且这个存取规则和数组的并不一样,所以就需要重新定义存取规则。这里用一个指针来实现栈结构的存储。

        定义一个指针,假设这个指针的名字叫a,一开始指针a指向的元素位置的索引为-1,即没有指向数组中的任何一个元素。当向数组中添加元素时,指针的位置就会向前移动,这样就实现了从一个端口添加元素。当完成添加元素的操作之后,假设已经添加了10个元素,此时最后一个元素的索引应该是9。当要取出元素时,让指针的位置向后移动,即如果取出一个元素,那么指针指向的元素的索引减一。所以进行获取数组中的元素的操作时,元素的索引的变化为9,8,7,6……-1。可以发现,最后添加的元素的索引为9,而它是最先被取出的,这样就实现了“后进先出”的规则。

        通过上面的描述,已经知道了实现一个栈结构的基本思路,接下来就来具体实现一个数据结构为栈结构的容器。参考java中已经有的栈容器,要实现一个栈容器需要实现几个基本的方法——empty(判断容器是否为空),pop(删除栈顶元素,并将栈顶元素返回),push(将指定的元素添加到栈容器中)。

        接下来创建一个栈容器结构,因为在执行添加元素的操作时添加的元素类型是不确定的,为了提高代码的复用性,这里应该将栈容器类定义为一个泛型类。然后根据上面的描述,需要定义一个私有数组来存储数据,这个数组的类型应该采用Object,因为事先并不知道要存入的数据的具体类型,而且因为JDK1.8之后支持延迟加载的操作,就是当需要的时候才创建对象,所以这里可以不指定数组长度。为了方便后期对数组进行扩容操作,还需要指定一个数组的默认长度。此外,记录栈容器当中的元素的个数以及操作元素索引的指针这个两个变量也是必须的。

        创建完相关变量,接下来就可以对栈容器中的方法做出具体实现了。首先要实现的是添加元素的方法。因为在定义数组时并没有给出数组的大小,因此要实现添加元素的方法首先就要对数组进行初始化,然后还要将元素添加到容器中,并且此时应该记录元素的数目变化。这里要注意的是,数组的初始化并不是说创建一个简单的数组,因为要提高代码的复用性,在不知道后期究竟要添加多少个元素的情况下,初始化数组应该分为两个部分——在没有数组的情况下创建一个新的数组用来存储添加进来的元素以及在已经有数组的情况下如果原数组的长度不够要对原数组进行扩容两个部分。这样这一个步骤的实现代码就比较长,为了提高代码的可读性应定义一个方法来实现数组的初始化操作。这个方法在演示代码中定义为capacity,在capacity中难点在于理解数组的扩容操作。

        扩容操作中包括两个部分,第一个部分,判断是否需要进行扩容操作。这一部分采用的代码为this.size - (this.defaultLength-1) >= 0,其中this.size指的是当前的元素个数,this.defahltLength指的是数组长度,减去1即(this.defaultLength-1)指的是数组的最大索引数。可能会有人认为这里的判断有问题,觉得当前元素个数减去数组的最大索引数这个判断条件不严谨,但是要注意一个问题,那就是如果数组长度已经不能存储元素了,那么就会提示数组元素溢出了。所以应该在数组还没有被存满的情况下进行扩容操作。第二个部分就是进行扩容的部分了,这里采用的代码为        this.defaultLength = this.defaultLength + (this.defaultLength>>1);
            this.arr = Arrays.copyOf(this.arr,this.defaultLength);

第一行代码中的右位移运算符>>的意思是除以2,所以这一行代码之后,原数组的长度就被扩充到了原来的1.5倍。第二行是数组的拷贝操作,也就是将原数组的内容拷贝到新的数组中去的操作。

        完成了数组的初始化,接下来就需进行添加元素的操作了。这里就是一个简单的赋值操作,因为一开始指针指向的位置为-1,并不是数组中的下标,所以在进行赋值操作之前要先移动指针的位置,具体体现在代码this.arr[++index] = item;中。元素个数的记录就极为简单了,只需要在完成添加元素的操作之后记录个数的变量加一即可。

        实现了栈容器中最难实现的添加元素的方法,相对简单的获取元素的方法pop和判断容器是否为空的方法就很简单了。pop方法的内容是返回栈顶元素,因此在返回栈顶元素之前必须要判断容器是否为空,如果元素为空系统就要抛出一个异常,这个异常在java自带的栈容器中有,这里只需要导入即可。而判断容器是否为空也很简单,只需要看指针是否指向-1就行。如果容器不为空,则返回栈顶元素,也就是此时指针指向的元素,返回后指针需要向前一个元素进行移动,具体体现在代码return (E)this.arr[index--];中。这里要说明的是,栈容器中用pop方法取出容器后元素数量会减少,因此应该对size变量进行对应操作。此外,因为定义的数组为Object型,所以取出元素时要对数组进行强制转型。

        有了上面的基础,判断栈容器是否为空的方法就超级简单了,只需要根据指针的位置是否在-1的位置上做出相应的判断即可。

import java.util.Arrays;
import java.util.EmptyStackException;


/**
 * 自定义栈容器
 */


public class MyStack<E> {
    private Object[] arr;//存放元素的物理结构
    private int defaultLength = 4;//数组的默认长度
    public  int size;//记录栈容器的元素个数
    private int  index = -1;//操作数组索引位置的指针
    /**
     * 向容器中添加元素
     */
    public E push(E item){
        //初始化数组
        this.capacity();
        //添加元素
        this.arr[++index] = item;
        //记录元素个数
        this.size++;
        return item;
    }
    /**
     * 数组初始化或者以1.5倍容量扩容
     */
    private void capacity(){
        //数组初始化
        if(this.arr == null){
            this.arr = new Object[defaultLength];
        }
        //数组扩容
        if(this.size - (this.defaultLength-1) >= 0){
            this.defaultLength = this.defaultLength + (this.defaultLength>>1);
            this.arr = Arrays.copyOf(this.arr,this.defaultLength);
        }
    }
    /**
     * 获取栈顶元素
     */
    public E pop(){
        //如果容器为空,抛出异常
        if(index == -1){
            throw new EmptyStackException();
        }
        //记录元素个数
        this.size--;
        //返回元素
        return (E)this.arr[index--];
    }
    /**
     * 判断容器是否为空
     */
    public boolean empty(){
        return this.size == 0;
    }

}

        至此,我们就创建出了一个栈容器类了,为了验证我们创建的栈容器类是否合理,我们创建一个测试类来对其中的方法进行测试。具体结果如下:

package com.data.demo;

public class MyStackTest {
    public static void main(String[] args) {
        MyStack<String> myStack = new MyStack<>();
        myStack.push("a");
        myStack.push("b");
        myStack.push("c");
        myStack.push("d");
        myStack.push("e");
        myStack.push("f");
        System.out.println(myStack.empty());
        System.out.println(myStack.size);
        System.out.println(myStack.pop());
        System.out.println(myStack.pop());
        System.out.println(myStack.pop());
        System.out.println(myStack.pop());
        System.out.println(myStack.pop());
        System.out.println(myStack.pop());
        System.out.println(myStack.empty());

    }
}

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

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

相关文章

构建高效业财一体化管理体系

构建高效业财一体化管理体系 业财一体化战略意义 提升决策质量 强化数据支撑&#xff1a;通过整合业务与财务数据&#xff0c;为决策提供准确、实时的信息基础&#xff0c;确保分析的深度与广度。促进业务与财务协同&#xff1a;打破信息孤岛&#xff0c;实现业务流程与财务管…

最流行的文件同步软件

PanguFlow是一款免费的文件同步软件&#xff0c;他支持文件的全量同步、支持文件的增量同步、支持文件的实时备份&#xff0c;支持双向同步&#xff0c;支持三向同步甚至多向同步&#xff0c;支持无人值守运行。 PanguFlow数据同步软件下载地址https://pan.baidu.com/s/1GLjFR…

博客都在使用的打字机效果,居然这么简单?

效果展示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>body …

在Ubuntu下将pulseaudio换成pipewire

1、为什么要将pulseaudio换成pipewire&#xff1f; PulseAudio 是一个成熟且广泛使用的音频服务器&#xff0c;适合一般桌面音频需求&#xff0c;但在性能和延迟上有一定限制。PipeWire 是一个更现代的解决方案&#xff0c;旨在统一音频和视频处理&#xff0c;提供高性能和低延…

【TB作品】密码锁,ATMEGA128单片机,Proteus仿真

题目 5 &#xff1a;密码锁 使用单片机实现简易密码锁&#xff0c;通过输入密码&#xff0c;实现门锁的开启&#xff08;控制继电器&#xff09;。 具体要求如下&#xff1a; &#xff08;1&#xff09;当输入正确密码后&#xff0c;继电器开启。 &#xff08;2&#xff09;当三…

Java web应用性能分析之【prometheus监控K8s指标说明】

常规k8s的监控指标 单独 1、集群维度 集群状态集群节点数节点状态&#xff08;正常、不可达、未知&#xff09;节点的资源使用率&#xff08;CPU、内存、IO等&#xff09; 2、应用维度 应用响应时间 应用的错误率 应用的请求量 3、系统和集群组件维度 API服务器状态控…

springcloud第4季 seata报could not find any implementation for class

一 问题说明 1.1 描述 在使用seata2.0alibaba-cloud 2022.0.0.0-RC2nacos 2.2.3 模拟下订单分布式事务场景&#xff0c;出现如下问题&#xff1a;java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0 查看服务端&#xff1a;java.util.ServiceCo…

【每日刷题】Day78

【每日刷题】Day78 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 1608. 特殊数组的特征值 - 力扣&#xff08;LeetCode&#xff09; 2. 1385. 两个数组间的距离值 - …

5.x86游戏实战-CE定位基地址

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;4.x86游戏实战-人物状态标志位 上一个内容通过CE未知的初始值、未变动的数值、…

在我们的大数据平台(XSailbaot)上进行企业级数据建模的思路

1. 背景 笔者所在的公司是差不多二十年前搞CIM&#xff08;公共信息模型的&#xff09;起家的。当时公司的前辈搞了基于CIS协议的模型服务器、数据服务器、模式编辑器等&#xff0c;形成了一套基于公共信息模型建模的平台系统。其中可视化建模&#xff0c;建好了模式类以后&am…

《昇思25天学习打卡营第17天 | 昇思MindSporeCycleGAN图像风格迁移互换》

17天 本节学习了CycleGAN图像风格迁移互换。 CycleGAN即循环对抗生成网络&#xff0c;该模型实现了一种在没有配对示例的情况下学习将图像从源域 X 转换到目标域 Y 的方法。该模型一个重要应用领域是域迁移&#xff0c;可以通俗地理解为图像风格迁移。其实在 CycleGAN 之前&a…

力扣每日一题 6/30 记忆化搜索/动态规划

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;IT竞赛 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 494.目标和【中等】 题目&#xff1a; 给你一个非负整数数组 nums 和一个…

⭐ UI自动化工具轻松实现微信消息提醒 ⚡

&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f; 演示效果 &#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f; &#x1f605;&#x1f605;&#x1f605;&#x1f605;&#x1f605;&#x1f605; Python安装…

nvm安装以及idea下vue启动项目过程和注意事项

注意1&#xff1a;nvm版本不要太低&#xff0c;1.1.7会出现下面这个问题&#xff0c;建议1.1.10及其以上版本 然后安装这个教程安装nvm和node.js 链接: nvm安装教程&#xff08;一篇文章所有问题全搞定&#xff0c;非常详细&#xff09; 注意2&#xff1a;上面的教程有一步骤…

魔行观察-烤匠麻辣烤鱼-开关店监测-时间段:2011年1月 至 2024年6月

今日监测对象&#xff1a;烤匠麻辣烤鱼&#xff0c;监测时间段&#xff1a;2011年1月 至 2024年6月 本文用到数据源获取地址 魔行观察http://www.wmomo.com/ 品牌介绍&#xff1a; 2013年&#xff0c;第一家烤匠在成都蓝色加勒比广场开业&#xff0c;随后几年成都国金中心店…

《昇思25天学习打卡营第15天 | 昇思MindSpore基于MindSpore的红酒分类实验》

15天 本节学了通过MindSpore的完成红酒分类。 1.K近邻算法&#xff08;K-Nearest-Neighbor, KNN&#xff09;是一种用于分类和回归的非参数统计方法&#xff0c;是机器学习最基础的算法之一。 1.1分类问题 1.2回归问题 1.3距离的定义 2.数据处理 2.1 数据准备 2.2 数据读取与处…

Spark join数据倾斜调优

Spark中常见的两种数据倾斜现象如下 stage部分task执行特别慢 一般情况下是某个task处理的数据量远大于其他task处理的数据量&#xff0c;当然也不排除是程序代码没有冗余&#xff0c;异常数据导致程序运行异常。 作业重试多次某几个task总会失败 常见的退出码143、53、137…

【C语言 || 数据结构】快速排序

文章目录 前言快速排序1.快排的前后指针法1.1快排的前后指针法的代码实现1.2快排的前后指针法的注意事项 2.快排的挖坑法2.1快排的挖坑法的代码实现2.2快排的挖坑法的注意事项 3.快排的hoare法3.1快排的hoare法的代码实现3.2快排的hoare法的注意事项 4快排的优化4.1快排的三数取…

恢复机制-数据库系统中的故障(事务故障、系统故障、介质故障)、一致性错误、窃取但不强制的缓冲区管理策略

一、引言 数据库管理系统DBMS的事务处理技术实现的一个主要功能部分就是恢复机制&#xff0c;恢复机制完成的功能就是对发生故障后系统中事务的更新结果进行数据恢复&#xff0c;保证事务的原子性和持久性&#xff0c;从而进一步保证数据库的一致性。 数据库系统与其他计算机系…

办公开源利器:ONLYOFFICE

目录 0、引子&#xff1a;一、ONLYOFFICE协作空间1.可集成至Web应用程序2.多种协作方式3.快捷的AI助手4.公共房间&#xff1a;连接第三方存储空间5.集成6.开发人员工具7.用插件拓展功能 二、新增功能1.功能全面的PDF编辑2.PDF 表单3.文本文档编辑器4.电子表格编辑器 三、结语 0…