算法通过村第四关-栈青铜笔记|手写栈操作

文章目录

  • 前言
  • 1. 栈的基础概要
    • 1.1 栈的特征
    • 1.2 栈的操作
    • 1.3 Java中的栈
  • 2. 栈的实现(手写栈)
    • 2.1 基于数组实现
    • 2.2 基于链表实现
    • 2.3 基于LinkedList实现
  • 总结


前言


提示:我自己一个人的感觉很好 我并不想要拥有你 除非你比我的独处更加宜人 --瓦尔桑·希雷

1. 栈的基础概要

1.1 栈的特征

栈和队列是比较特殊的线性表,为什么特殊呢?(又称为访问受限的线性表)。栈常用于表达式、符号等运算的基础,也是递归的底层实现。理论上递归可以做的题目栈都是可以做的,只是有些问题用栈相对复杂一些。

栈的底层实现是我们常见的链表或者顺序表,栈与线性表的最大区别在于数据的存取操作被限制了,其插入和删除操作只允许在线性表的一端进行。一般而言,我们把允许操作的一端称为栈顶(top),不可以操作的一端称为栈底(bottom),同时插入元素的操作称为入栈(push)删除元素的操作称为出栈(pop)。若栈中没有任何元素,则称为空栈,栈的结构如图所示:
在这里插入图片描述

1.2 栈的操作

栈的常见操作主要有:

  • push(E):增加一个元素E
  • pop():弹出元素E
  • peek():显示栈顶元素,但是不出栈
  • empty():判断栈是否为空

我们在设计自己的栈的时候,不管是使用数组还是链表,都需要实现以上的几个方法。

一道经典的题目,入栈顺序为1234,所有可能的出栈序列是什么?

这个题是什么意思呢?举个例子,我们可以先让1,2入栈,然后2,1出栈,再让3,4入栈,然后一次出栈,就可以得到2143的序列。

4个元素的全排列有4!= 24,栈要求符合先进后出,根据这个条件我们可以排除:

1234 √ 1243 √ 1324 √ 1342 √ 1423 × 1432 √

2134 √ 2143 √ 2314 √ 2341 √ 2413 × 2431 √

3124 × 3142 × 3214 √ 3241 √ 3412 × 3421 √

4123 × 4132 × 4213 × 4231 × 4312× 4321 √

14中可能,10中不可能。

1.3 Java中的栈

Java中的栈,uitl中就提供了栈Stack类,使用起来也不复杂,我们看一下例子:


import java.util.Stack;

public class MainTest {
    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();
        // 入栈
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        // 出栈
        stack.pop();
        while (!stack.isEmpty()) {
            // 展示但是不删除
            System.out.println(stack.peek());
            // 删除
            System.out.println(stack.pop());
        }

    }
}

2. 栈的实现(手写栈)

我们在学习栈的过程中,需要了解一些问题,top栈顶指针的指向,有的地方指向栈顶再往上一个空位,有的地方指向栈顶元素。我们确定好设计就行,(根据题目调整,有时候也可以直接问面试官 top指向哪里)这里采用指向栈顶空位置。

如果我们自己要实现栈,可以使用数组,链表Java中提供了LinkedList三种基本实现方式,我们都可以看一下。

2.1 基于数组实现

采用顺序表实现的栈,内部以数组为基础,实现对元素的存取操作。在应用中还要之一每次入栈之前要确保栈的容量是否足够,不够需要考虑扩容的问题。

我们画一下入栈的过程:
在这里插入图片描述
出栈的过程:
在这里插入图片描述
出栈先将栈顶元素取出,然后top–

展示代码:

import java.util.Arrays;class Mystack<T> {
    private Object[] stack;
    // 栈顶指针
    private int top;public Mystack() {
        // 初始长度为10
        stack = new Object[10];
    }/**
     * 判断是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return top == 0;
    }/**
     * 返回栈顶元素但是不删除
     *
     * @return
     */
    public T peek() {
        T t = null;
        if (top > 0) {
            t = (T) stack[top - 1];
        }
        return t;
    }/**
     * 入栈操作
     *
     * @param t
     */
    public void push(T t) {
        expandCapacity(top + 1);
        stack[top] = t;
        top++;
    }public T pop() {
        T t = peek();
        if (!isEmpty()) {
            // 清除元素
            stack[top - 1] = null;
            top--;
        }
        return t;
    }/**
     * 确保容量
     *
     * @param size
     */
    public void expandCapacity(int size) {
        int len = stack.length;
        if (size > len) {
            size = size * 3 / 2 + 1;
            stack = Arrays.copyOf(stack, size);
        }
    }
​
​
​
​
    public static void main(String[] args) {
        Mystack<String> stack = new Mystack<>();
        System.out.println(stack.peek());// null
        System.out.println(stack.isEmpty());// true
        stack.push("java");
        stack.push("is");
        stack.push("beautiful");
        stack.push("language");
        System.out.println(stack.pop());// language
        System.out.println(stack.isEmpty());// false
        System.out.println(stack.peek()); // beautiful
    }
}

2.2 基于链表实现

链表用来实现栈也很简单,头插法(在头部操作链表就可以了)。
我们先画个图:

在这里插入图片描述
在链表的那一章我们介绍过没有虚拟节点时对链表头部元素进行插入和删除的操作,不记得的可以回顾一下算法通过村第二关-链表青铜笔记_师晓峰的博客-CSDN博客,这里基于链表实现栈的操作时完全一样的。

代码实现:

class ListStack<T> {

    // 构造节点
    class Node<T> {
        public T t;
        private Node next;
    }

    public Node<T> head;

    ListStack() {
        head = null;
    }

    /**
     * 入栈操作
     * @param t
     */
    public void push(T t) {
        if (t == null) {
            throw new IllegalStateException("参数不能为空");
        }
        // 头节点为空
        if (head == null) {
            head = new Node<T>();
            head.t = t;
            head.next = null;
        }else {
            Node<T> temp = head;
            head = new Node<T>();
            head.t = t;
            head.next = temp;
        }
    }

    /**
     * 出栈操作
     * @return
     */
    public T pop(){
        if (head == null) {
            return null;
        }
        T t = head.t;
        head = head.next;
        return t;
    }

    public T peek(){
        if (head == null) {
            return null;
        }
        return head.t;
    }


    /**
     * 判断是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return head == null;
    }

    public static void main(String[] args) {
        ListStack stack = new ListStack();
        System.out.println(stack.isEmpty());// true
        stack.push("Java");
        stack.push("is");
        stack.push("beautiful");
        System.out.println(stack.peek());// beautiful
        System.out.println(stack.pop());// beautiful
        System.out.println(stack.isEmpty());// false
    }
}

2.3 基于LinkedList实现

这里就很简单了,直接上代码就行;

import java.util.LinkedList;

/**
 * 基于Java的LinkedList来实现栈
 * @param <T>
 */
public class LinkedListStack<T> {

    private LinkedList<T> ll;
    LinkedListStack(){
        ll = new LinkedList<T>();
    }

    /**
     * 入栈操作
     * @param t
     */
    public void push( T t){
         ll.addFirst(t);
    }

    /**
     * 出栈但是不删除
     * @return
     */
    public T peek(){
        T t = null;
        if (!ll.isEmpty()){
            t = ll.peek();
        }
        return t;
    }

    public T  pop(){
       return ll.removeFirst();
    }


    public boolean isEmpty(){
        return ll.isEmpty();
    }


    public static void main(String[] args) {
        LinkedListStack<String> stack = new LinkedListStack();
        System.out.println(stack.isEmpty());//true
        System.out.println(stack.peek());//null
        stack.push("java");
        stack.push("is");
        stack.push("beautiful");
        System.out.println(stack.peek());//beautiful
        System.out.println(stack.pop());//beautiful
        System.out.println(stack.isEmpty());//false
    }
}


总结

提示:记住栈的特性,先进后出

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

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

相关文章

探索生成式人工智能的前景

一、什么是生成式人工智能&#xff1f; 生成式人工智能&#xff08;Generative AI&#xff09;是一类人工智能&#xff08;AI&#xff09;技术和模型&#xff0c;旨在创建新颖的内容。与简单的复制不同&#xff0c;这些模型通过利用从训练数据集中收集到的模式和见解&#xff…

nginx-concat

为了减少tcp请求数量&#xff0c;nginx从上有服务器获取多个静态资源&#xff08;css&#xff0c;js&#xff09;的时候&#xff0c;将多个静态资源合并成一个返回给客户端。 这种前面有两个问号的请求都是用了cancat合并功能。 先到官网下载安装包&#xff0c;拷贝到服务器编译…

弯道超车必做好题集锦三(C语言选择题)

前言&#xff1a; 编程想要学的好&#xff0c;刷题少不了&#xff0c;我们不仅要多刷题&#xff0c;还要刷好题&#xff01;为此我开启了一个弯道超车必做好题锦集的系列&#xff0c;每篇大约10题左右。此为第三篇选择题篇&#xff0c;该系列会不定期更新&#xff0c;后续还会…

C#_特性反射详解

特性是什么&#xff1f; 为程序元素额外添加声明信息的一种方式。 字面理解&#xff1a;相当于把额外信息写在干胶标签上&#xff0c;然后将其贴在程序集上。 反射是什么&#xff1f; 反射是一种能力&#xff0c;运行时获取程序集中的元数据。 字面理解&#xff1a;程序运行…

防溺水智能预警系统解决方案 yolov7

防溺水智能预警系统解决方案采用yolov7先进的AI视觉识别算法模型框架&#xff0c;防溺水智能预警系统解决方案算法实现对危险水域人员活动、水面情况等各项指标的监测和分析。当发现有人进入危险水域或出现紧急情况时&#xff0c;算法会立即发出预警信号。Yolo算法采用一个单独…

Android Glide preload RecyclerView切入后台不可见再切换可见只加载当前视野可见区域item图片,Kotlin

Android Glide preload RecyclerView切入后台不可见再切换可见只加载当前视野可见区域item图片&#xff0c;Kotlin <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name"android.permission.RE…

使用Nacos与Spring Boot实现配置管理

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Qt6和Rust结合构建桌面应用

桌面应用程序是原生的、快速的、安全的&#xff0c;并提供Web应用程序无法比拟的体验。 Rust 是一种低级静态类型多范式编程语言&#xff0c;专注于安全性和性能&#xff0c;解决了 C/C 长期以来一直在努力解决的问题&#xff0c;例如内存错误和构建并发程序。 在桌面应用程序开…

单片机电子元器件-数码管

数码管分类 共阳 把所有数码管的阳极接到一起形成公共阳极COM 数码管 共阳极COM 接到 5V 电源 共阴 把所有数码管的阴极接到一起形成公共阴极COM 数码管 共阴极COM 接到 地 GND 上 八段 数码管 和 七段数码管&#xff0c; 多了一个 小数点 DP 数码管显示原理 一个数码管如…

uniapp项目实战系列(2):新建项目,项目搭建,微信开发工具的配置

目录 系列文章目录uniapp项目实战系列(1)&#xff1a;导入数据库&#xff0c;启动后端服务&#xff0c;开启代码托管&#xff08;点击跳转&#xff09;1.新建项目2.托管项目的操作&#xff1a;&#xff08;无勾选托管项目可无视&#xff09;3.项目编译预览3.1游览器编译3.2微信…

C. Battle 2023 (ICPC) Jiangxi Provincial Contest -- Official Contest

Problem - C - Codeforces 题目大意&#xff1a;有n堆石子&#xff0c;给出一个数p&#xff0c;A先B后&#xff0c;每个人每次只能取p的幂个石子&#xff08;包括1&#xff09;问A能不能赢 1<n<3e5;1<p<1e18 思路&#xff1a;先递归算出sg函数看看&#xff0c;s…

python 笔记(1)——基础和常用部分

目录 1、print 输出不换行 2、格式化输出字符串 3、浮点数的处理 4、进制转换和ASCII与字符间的转换 5、随机数 6、字符串截取和内置方法 6-1&#xff09;字符串截取 6-2&#xff09;字符串内置方法 7、元组、列表&#xff0c;及其遍历方式 7-1&#xff09;列表常用内…

使用Python构建网络爬虫:提取网页内容和图片资源

网络爬虫是一种自动获取网页内容的程序&#xff0c;它可以帮助我们高效地收集网络上的有价值信息。本文将介绍如何使用Python构建网络爬虫&#xff0c;提取网页内容和图片资源。   一、环境准备   1.安装Python环境   首先&#xff0c;确保您已经安装了Python环境。访问P…

可控硅调功电路原理

在常见的马达调速以及需要调整负载功率的场合&#xff0c;经常会用到可控硅调功电路&#xff0c;下图是常见的应用电路。 调功电路主要由阻容移相电路和可控硅触发电路构成&#xff0c;工作过程如下&#xff0c;当交流电的正半周时&#xff0c;交流电通过R5,可调电阻R3给电容C1…

java对时间序列根据阈值进行连续性分片

问题描述&#xff1a;我需要对一个连续的时间戳list进行分片&#xff0c;分片规则是下一个数据比当前数据要大于某一个阈值则进行分片&#xff1b; 解决方式&#xff1a; 1、输入的有顺序的list &#xff0c;和需要进行分片的阈值 2、调用方法&#xff0c;填入该排序的list和阈…

十种高级的代码书写方式,提高代码质量和工作效率

1.集合遍历 不使用lambda&#xff1a; List<String> list Arrays.asList("kk", "oneone", "11"); for (String name : list) {System.out.println(name); }使用lambda&#xff1a; List<String> list Arrays.asList("kk&q…

19 NAT穿透|python高级

文章目录 网络通信过程NAT穿透 python高级GIL锁深拷贝与浅拷贝私有化import导入模块工厂模式多继承以及 MRO 顺序烧脑题property属性property装饰器property类属性 魔法属性\_\_doc\_\_\_\_module\_\_ 和 \_\_class\_\_\_\_init\_\_\_\_del\_\_\_\_call\_\_\_\_dict\_\_\_\_str…

【爬虫小知识】如何利用爬虫爬网页——python爬虫

前言 网络时代的到来&#xff0c;给我们提供了海量的信息资源&#xff0c;但是&#xff0c;想要获取这些信息&#xff0c;手动一个一个网页进行查找&#xff0c;无疑是一项繁琐且效率低下的工作。这时&#xff0c;爬虫技术的出现&#xff0c;为我们提供了一种高效的方式去获取…

怎么入门网络安全(黑客)?

目录&#xff1a; 一、自学网络安全学习的误区和陷阱 1.不要试图先成为一名程序员&#xff08;以编程为基础的学习&#xff09;再开始学习2.不要把深度学习作为入门第一课3.以黑客技能、兴趣为方向的自学误区&#xff1a;4.不要收集过多的资料二、学习网络安全的一些前期准备三…

Kubernetes入门 十二、网络之Ingress

目录 概述安装 Ingress使用 Ingress准备工作部署Ingress设置默认后端Ingress 中的 nginx 的全局配置限流路径重写基于 Cookie 的会话保持技术配置 SSL 概述 通常情况下&#xff0c;service 和 pod 的 IP 仅可在集群内部访问。 Service 可以也使用 NodePort 暴露集群外访问端口…