数据结构与算法——14.栈

2023-09-21 21:58:02

目录

1.概述

2.栈的接口设计

3.用链表来实现栈

4.用数组来实现栈

5.用两个栈来实现一个队列

6.用一个队列来实现一个栈

7.总结

1.概述

计算机科学中,stack是一种线性的数据结构,只能在其一端添加数据和移除数据。习惯来说,这一端称之为栈顶,另一端不能操作数据的称之为栈底,就如同生活中的一摞书。

说明:栈是线性的,只能在一端进行操作,分为栈顶和栈底两部分,包括入栈和出栈操作。

2.栈的接口设计

下面看一下栈的接口设计:

很简单,就是入栈,出栈,判断是否为空等操作。

3.用链表来实现栈

下面看一下如何用链表来实现栈:

代码:



public class L12_LinkedListStack<E> implements L12_Stack<E> {

    /**定义节点类*/
    public  class Node{
        E value;
        Node next;

        public Node() {
        }

        public Node(E value, Node next) {
            this.value = value;
            this.next = next;
        }
    }

    private int capacity;//栈的容量
    private int size;//栈中有效数据个数
    Node head = new Node(null,null);

    /*向栈顶添加元素*/
    @Override
    public boolean push(E value) {
        if(isFUll())
            return false;
        Node node = new Node(value, head.next);
        head.next = node;
        size++;
        return true;
    }

    /*弹出栈顶的元素*/
    @Override
    public E pop() {
        if (isEmpty())
            return null;
        Node p = head.next;
        head.next = p.next;
        size--;
        return p.value;
    }

    /*返回栈顶元素*/
    @Override
    public E peek() {
        if (isEmpty())
            return null;
        return head.next.value;
    }

    @Override
    public boolean isEmpty() {
        return head.next==null;
    }

    @Override
    public boolean isFUll() {
        return size == capacity;
    }
}

说明:总的来说还是很简单的,只要会链表的相关操作,那么就可以轻松实现

4.用数组来实现栈

下面来看一下如何用数组来实现栈:

代码:
 



public class L12_ArrayStack<E> implements L12_Stack<E>{

    private E[] array;
    private int top;//栈顶指针

    public L12_ArrayStack(int capacity) {
        this.array = (E[])new Object[capacity];
    }

    @Override
    public boolean push(E value) {
        if (isFUll())
            return false;
        array[top] = value;
        top++;
        return true;
    }

    @Override
    public E pop() {
        if (isEmpty())
            return null;
        E value = array[--top];
        //top--;
        return value;
    }

    @Override
    public E peek() {
        if (isEmpty())
            return null;
        return array[top-1];
    }

    @Override
    public boolean isEmpty() {
        return top == 0 ;
    }

    @Override
    public boolean isFUll() {
        return top == array.length;
    }
}

说明:用数组实现栈也很简单。其中的关键点就是定义了一个指针top,你可以理解其为指针,也可以理解其为栈中有效元素的个数。这就是数组来实现一些线性数据的好处,数组的元素个数相当于一个指针,一个指针的值也相当于数组中元素的个数。

5.用两个栈来实现一个队列

下面俩看一下如何用两个栈来模拟一个队列:

代码:

public class L13_TwoStackToQueue {

    L12_ArrayStack<Integer> s1 = new L12_ArrayStack(100);//前半个
    L12_ArrayStack<Integer> s2 = new L12_ArrayStack(100);//后半个

    /**入队操作,就是直接在后半个栈中压栈就行*/
    public void push(int x){
        s2.push(x);
    }
    /**出队操作*/
    public int pop(){
        if (s1.isEmpty()){
            while (!s2.isEmpty()){
                s1.push(s2.pop());
            }
        }
        return s1.pop();
    }

    /**返回队首元素*/
    public int peek(){
        if (s1.isEmpty()){
            while (!s2.isEmpty()){
                s1.push(s2.pop());
            }
        }
        return s1.peek();
    }

    public boolean empty(){
        return s1.isEmpty() && s2.isEmpty();
    }
}

说明:

栈只有一端可以操作,是先入后出的,队列是两端都可以操作,是先入先出的。那么肯定要有两个栈,一个做队首,一个做队尾。入队操作就是后面栈的入栈操作。关键在与于出队。我们可以将后面栈的元素依次出栈,然后再将这些元素依次压入到前面的一个栈中,这样就改变了元素的顺序,再使用前面一个栈的出栈操作,就实现了出队操作。判断空就是两个栈都为空时队列才为空。

6.用一个队列来实现一个栈

下面来看一下如何用一个队列来实现一个栈:

代码:


public class L14_QueueToStack {

    L9_ArrayQueue1<Integer> q1 = new L9_ArrayQueue1(100);
    private int size = 0;//记录队列中元素的个数

    public void push(int x){
        q1.offer(x);
        for (int i = 0; i < size; i++) {
            q1.offer(q1.poll());
        }
        size++;
    }

    public int poll(){
        size--;
        return  q1.poll();
    }

    public int pop(){
        return q1.peek();
    }

    public boolean empty(){
        return q1.isEmpty();
    }
}

说明:

首先,我们要明确哪里是栈顶,哪里相当于栈底。结合题目看,队首为栈顶,队尾为栈底。这个实现的关键在与入栈操作。当我们从队尾入队后,前面已经入队的元素就跑到栈顶了,这不符合栈的规则。怎么才能让后入的元素在栈顶即在队首?我们可以将前面已经入队的元素依次弹出,然后再将这些元素依次入队,这样我们新加入的元素就这栈顶了,也就是队首了。然后出栈操作和判断空就很简单了。

7.总结

栈其实也很简单。就是很简单入栈,出栈等操作。栈是单端口操作的数据结构,入栈和出栈都只在一个端口。栈可以用链表和数组来实现。栈的特点就是先入后出。

暂时就这么多吧

更多推荐

ubuntu中如何用docker下载华为opengauss数据库(超简单)

ubuntu中如何下载华为opengauss数据库前言一、安装docker1.方法一:2.方法二二、拉取openguass镜像三、创建容器四、连接数据库,切换到omm用户,用gsql连接到数据库五.最后用DateGrip远程连接测试(1)选择数据源(2)查看虚拟机ip地址(3)远程连接测试前言openGauss是一款全

家居行业如何借助AI营销数智化转型?《2023 家居行业AI营销第一课(重庆站)》给你答案

商务部将2023年定为“消费提振年”。作为仅次于汽车消费的家庭第二大消费支出,家居产业的高质量发展与扩大内需提振消费息息相关。随着今年利好政策不断发布,家居建材行业的市场环境及消费潜力得到大幅度改善。随着ChatGPT等新技术的出现与消费需求升级的趋势,近年来,家居建材行业数智化转型趋势越来越明显,家居行业的品牌营销也

基于SSM+Vue的网络教学平台的设计与实现的设计与实现

末尾获取源码开发语言:JavaJava开发工具:JDK1.8后端框架:SSM前端:采用Vue技术开发数据库:MySQL5.7和Navicat管理工具结合服务器:Tomcat8.5开发软件:IDEA/Eclipse是否Maven项目:是目录一、项目简介二、系统功能三、系统项目截图学生功能模块的实现管理员功能模块的实现教师

华纳云:Ubuntu下开启php调试模式报错如何解决

开启PHP调试模式时出现错误通常是由于PHP代码中的问题引起的。调试模式有助于发现和修复这些问题。以下是解决开启PHP调试模式时可能遇到的一些常见问题以及解决方法:错误报告级别设置不正确:PHP有不同的错误报告级别,开启调试模式时,建议将错误报告级别设置为最高,以捕获所有错误。您可以在PHP配置文件(php.ini)中

半导体行业如何在跨网数据交换时保证核心数据是安全的?

半导体行业是高科技产业的核心,也是国家战略的重点领域。半导体产业涉及到芯片设计、制造、封装、测试等多个环节,每个环节都需要大量的数据支撑和交换。半导体企业的核心数据不仅包括技术方案、设计图纸、生产参数等,还包括市场分析、客户信息、合作协议等。这些数据对于半导体企业的竞争力和发展至关重要,一旦泄露或损坏,将会给企业带来巨

【C++】bitset介绍与用法讲解

今日写csp,看大佬的题解中出现了bitset,以前有印象但没学,所以赶快去OI-wiki上补一下,并记录于此std::bitset是标准库中的一个存储0/1的大小不可变容器。严格来讲,它并不属于STL。TheC++standardlibraryprovidessomespecialcontainerclasses,t

Python绘制X-bar图和R图 | 统计过程控制SPC

X-bar图和R图是用于统计过程控制(SPC)的两种常用工具,用于监测过程的平均值和范围(变异性)。这些图有助于识别过程中的变化和异常,以便及时采取纠正措施。**X-bar图(平均值控制图)**显示了一系列样本的平均值,用于监测过程的平均值是否保持在可接受的范围内。X-bar图通常由以下几个要素组成:样本平均值:每个样

线程池的基本理解以及使用

首先线程池是一种管理和复用线程的机制,它可以用来提高多线程编程的效率和性能。线程池的概念:线程池是一种线程管理的机制,它通常由一个线程池管理器(ThreadPoolExecutor)和一组线程组成。线程池管理器负责创建、管理和调度线程。当任务到达时,线程池会从线程池中预先创建的线程中选一个来执行任务,如果没有空闲线程,

微调大型语言模型(一):为什么要微调(Why finetune)?

今天我们来学习Deeplearning.ai的在线课程微调大型语言模型(一)的第一课:为什么要微调(Whyfinetune)。我们知道像GPT-3.5这样的大型语言模型(LLM)它所学到的知识截止到2021年9月,那么如果我们向ChatGPT询问2022年以后发生的事情,它可能会产生“幻觉”从而给出错误的答案,再比如我

HTTP协议的请求方式有哪些

HTTP请求方式是指客户端向服务器发送请求时所使用的方法,常用的请求方式有GET、POST、PUT、DELETE、HEAD、OPTIONS等。这些请求方式各自有着不同的特点和用途,下面将逐一介绍。GET请求GET请求是最常用的请求方式,用于向服务器请求获取某个资源。GET请求的参数会附加在URL的后面,以问号(?)分隔

API接口大全:常用、热门、免费的都有

常用、热门、免费的第三方接口应有尽有…二次号查询:通过手机号查询是否二次入网,直连三大运营商,精准查询。反欺诈(羊毛盾):反机器欺诈,检测异常IP、异常手机号。IP应用场景-IPv4,IPv4应用场景是获取IP场景属性的在线调用接口,具备识别IP真人度,提升风控和反欺诈等业务能力。IP应用场景基于地理和网络特征的IP场

热文推荐