【数据结构-栈】栈基础

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
img

  • 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老
  • 导航
    • 檀越剑指大厂系列:全面总结 java 核心技术点,如集合,jvm,并发编程 redis,kafka,Spring,微服务,Netty 等
    • 常用开发工具系列:罗列常用的开发工具,如 IDEA,Mac,Alfred,electerm,Git,typora,apifox 等
    • 数据库系列:详细总结了常用数据库 mysql 技术点,以及工作中遇到的 mysql 问题等
    • 懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
    • 数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

博客目录

    • 一.栈介绍
      • 1.概述
      • 2.链表实现
      • 3.数组实现
      • 4.应用
    • 二.栈题目
      • 1.有效的括号-力扣 20 题
      • 2.后缀表达式求值-力扣 120 题
      • 3.中缀表达式转后缀
      • 4.双栈模拟队列-力扣 232 题
      • 5.单队列模拟栈-力扣 225 题

一.栈介绍

1.概述

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

先提供一个栈接口

public interface Stack<E> {/*** 向栈顶压入元素* @param value 待压入值* @return 压入成功返回 true, 否则返回 false*/boolean push(E value);/*** 从栈顶弹出元素* @return 栈非空返回栈顶元素, 栈为空返回 null*/E pop();/*** 返回栈顶元素, 不弹出* @return 栈非空返回栈顶元素, 栈为空返回 null*/E peek();/*** 判断栈是否为空* @return 空返回 true, 否则返回 false*/boolean isEmpty();/*** 判断栈是否已满* @return 满返回 true, 否则返回 false*/boolean isFull();
}

2.链表实现

public class LinkedListStack<E> implements Stack<E>, Iterable<E> {private final int capacity;private int size;private final Node<E> head = new Node<>(null, null);public LinkedListStack(int capacity) {this.capacity = capacity;}@Overridepublic boolean push(E value) {if (isFull()) {return false;}head.next = new Node<>(value, head.next);size++;return true;}@Overridepublic E pop() {if (isEmpty()) {return null;}Node<E> first = head.next;head.next = first.next;size--;return first.value;}@Overridepublic E peek() {if (isEmpty()) {return null;}return head.next.value;}@Overridepublic boolean isEmpty() {return head.next == null;}@Overridepublic boolean isFull() {return size == capacity;}@Overridepublic Iterator<E> iterator() {return new Iterator<E>() {Node<E> p = head.next;@Overridepublic boolean hasNext() {return p != null;}@Overridepublic E next() {E value = p.value;p = p.next;return value;}};}static class Node<E> {E value;Node<E> next;public Node(E value, Node<E> next) {this.value = value;this.next = next;}}
}

3.数组实现

public class ArrayStack<E> implements Stack<E>, Iterable<E>{private final E[] array;private int top = 0;@SuppressWarnings("all")public ArrayStack(int capacity) {this.array = (E[]) new Object[capacity];}@Overridepublic boolean push(E value) {if (isFull()) {return false;}array[top++] = value;return true;}@Overridepublic E pop() {if (isEmpty()) {return null;}return array[--top];}@Overridepublic E peek() {if (isEmpty()) {return null;}return array[top-1];}@Overridepublic boolean isEmpty() {return top == 0;}@Overridepublic boolean isFull() {return top == array.length;}@Overridepublic Iterator<E> iterator() {return new Iterator<E>() {int p = top;@Overridepublic boolean hasNext() {return p > 0;}@Overridepublic E next() {return array[--p];}};}
}

4.应用

模拟如下方法调用

public static void main(String[] args) {System.out.println("main1");System.out.println("main2");method1();method2();System.out.println("main3");
}public static void method1() {System.out.println("method1");method3();
}public static void method2() {System.out.println("method2");
}public static void method3() {System.out.println("method3");
}

模拟代码

public class CPU {static class Frame {int exit;public Frame(int exit) {this.exit = exit;}}static int pc = 1; // 模拟程序计数器 Program counterstatic ArrayStack<Frame> stack = new ArrayStack<>(100); // 模拟方法调用栈public static void main(String[] args) {stack.push(new Frame(-1));while (!stack.isEmpty()) {switch (pc) {case 1 -> {System.out.println("main1");pc++;}case 2 -> {System.out.println("main2");pc++;}case 3 -> {stack.push(new Frame(pc + 1));pc = 100;}case 4 -> {stack.push(new Frame(pc + 1));pc = 200;}case 5 -> {System.out.println("main3");pc = stack.pop().exit;}case 100 -> {System.out.println("method1");stack.push(new Frame(pc + 1));pc = 300;}case 101 -> {pc = stack.pop().exit;}case 200 -> {System.out.println("method2");pc = stack.pop().exit;}case 300 -> {System.out.println("method3");pc = stack.pop().exit;}}}}
}

二.栈题目

1.有效的括号-力扣 20 题

一个字符串中可能出现 [] (){} 三种括号,判断该括号是否有效

有效的例子

()[]{}([{}])()

无效的例子

[)([)]([]

思路

  • 遇到左括号, 把要配对的右括号放入栈顶
  • 遇到右括号, 若此时栈为空, 返回 false,否则把它与栈顶元素对比
    • 若相等, 栈顶元素弹出, 继续对比下一组
    • 若不等, 无效括号直接返回 false
  • 循环结束
    • 若栈为空, 表示所有括号都配上对, 返回 true
    • 若栈不为空, 表示右没配对的括号, 应返回 false

答案(用到了课堂案例中的 ArrayStack 类)

public boolean isValid(String s) {ArrayStack<Character> stack = new ArrayStack<>(s.length() / 2 + 1);for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);if (c == '(') {stack.push(')');} else if (c == '[') {stack.push(']');} else if (c == '{') {stack.push('}');} else {if (!stack.isEmpty() && stack.peek() == c) {stack.pop();} else {return false;}}}return stack.isEmpty();
}

2.后缀表达式求值-力扣 120 题

后缀表达式也称为逆波兰表达式,即运算符写在后面

  • 从左向右进行计算
  • 不必考虑运算符优先级,即不用包含括号

示例

输入:tokens = ["2","1","+","3","*"]
输出:9
即:(2 + 1) * 3输入:tokens = ["4","13","5","/","+"]
输出:6
即:4 + (13 / 5)

题目假设

  • 数字都视为整数
  • 数字和运算符个数给定正确,不会有除零发生

代码

public int evalRPN(String[] tokens) {LinkedList<Integer> numbers = new LinkedList<>();for (String t : tokens) {switch (t) {case "+" -> {Integer b = numbers.pop();Integer a = numbers.pop();numbers.push(a + b);}case "-" -> {Integer b = numbers.pop();Integer a = numbers.pop();numbers.push(a - b);}case "*" -> {Integer b = numbers.pop();Integer a = numbers.pop();numbers.push(a * b);}case "/" -> {Integer b = numbers.pop();Integer a = numbers.pop();numbers.push(a / b);}default -> numbers.push(Integer.parseInt(t));}}return numbers.pop();
}

3.中缀表达式转后缀

#反编译可以看到执行指令的过程
javap -c -v .\E03InfixToSuffix.class
public class E03InfixToSuffix {/*思路1. 遇到数字, 拼串2. 遇到 + - * /- 优先级高于栈顶运算符 入栈- 否则将栈中高级或平级运算符出栈拼串, 本运算符入栈3. 遍历完成, 栈中剩余运算符出栈拼串- 先出栈,意味着优先运算4. 带 ()- 左括号直接入栈- 右括号要将栈中直至左括号为止的运算符出栈拼串|   ||   ||   |_____a+ba+b-ca+b*ca*b+c(a+b)*c*/public static void main(String[] args) {System.out.println(infixToSuffix("a+b"));System.out.println(infixToSuffix("a+b-c"));System.out.println(infixToSuffix("a+b*c"));System.out.println(infixToSuffix("a*b-c"));System.out.println(infixToSuffix("(a+b)*c"));System.out.println(infixToSuffix("a+b*c+(d*e+f)*g"));}static String infixToSuffix(String exp) {LinkedList<Character> stack = new LinkedList<>();StringBuilder sb = new StringBuilder(exp.length());for (int i = 0; i < exp.length(); i++) {char c = exp.charAt(i);switch (c) {case '+', '-', '*', '/' -> {if (stack.isEmpty()) {stack.push(c);} else {if (priority(c) > priority(stack.peek())) {stack.push(c);} else {while (!stack.isEmpty()&& priority(stack.peek()) >= priority(c)) {sb.append(stack.pop());}stack.push(c);}}}case '(' -> {stack.push(c);}case ')' -> {while (!stack.isEmpty() && stack.peek() != '(') {sb.append(stack.pop());}stack.pop();}default -> {sb.append(c);}}}while (!stack.isEmpty()) {sb.append(stack.pop());}return sb.toString();}static int priority(char c) {return switch (c) {case '(' -> 0;case '*', '/' -> 2;case '+', '-' -> 1;default -> throw new IllegalArgumentException("不合法字符:" + c);};}
}

4.双栈模拟队列-力扣 232 题

给力扣题目用的自实现栈,可以定义为静态内部类

class ArrayStack<E> {private E[] array;private int top; // 栈顶指针@SuppressWarnings("all")public ArrayStack(int capacity) {this.array = (E[]) new Object[capacity];}public boolean push(E value) {if (isFull()) {return false;}array[top++] = value;return true;}public E pop() {if (isEmpty()) {return null;}return array[--top];}public E peek() {if (isEmpty()) {return null;}return array[top - 1];}public boolean isEmpty() {return top == 0;}public boolean isFull() {return top == array.length;}
}

参考解答,注意:题目已说明

  • 调用 push、pop 等方法的次数最多 100
public class E04Leetcode232 {/*队列头      队列尾s1       s2顶   底   底   顶abcpush(a)push(b)push(c)pop()*/ArrayStack<Integer> s1 = new ArrayStack<>(100);ArrayStack<Integer> s2 = new 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();}}

5.单队列模拟栈-力扣 225 题

给力扣题目用的自实现队列,可以定义为静态内部类

public class ArrayQueue3<E> {private final E[] array;int head = 0;int tail = 0;@SuppressWarnings("all")public ArrayQueue3(int c) {c -= 1;c |= c >> 1;c |= c >> 2;c |= c >> 4;c |= c >> 8;c |= c >> 16;c += 1;array = (E[]) new Object[c];}public boolean offer(E value) {if (isFull()) {return false;}array[tail & (array.length - 1)] = value;tail++;return true;}public E poll() {if (isEmpty()) {return null;}E value = array[head & (array.length - 1)];head++;return value;}public E peek() {if (isEmpty()) {return null;}return array[head & (array.length - 1)];}public boolean isEmpty() {return head == tail;}public boolean isFull() {return tail - head == array.length;}
}

参考解答,注意:题目已说明

  • 调用 push、pop 等方法的次数最多 100
  • 每次调用 pop 和 top 都能保证栈不为空
public class E05Leetcode225 {/*队列头     队列尾cba顶           底queue.offer(a)queue.offer(b)queue.offer(c)*/ArrayQueue3<Integer> queue = new ArrayQueue3<>(100);int size = 0;public void push(int x) {queue.offer(x);for (int i = 0; i < size; i++) {queue.offer(queue.poll());}size++;}public int pop() {size--;return queue.poll();}public int top() {return queue.peek();}public boolean empty() {return queue.isEmpty();}
}

觉得有用的话点个赞 👍🏻 呗。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

img

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

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

相关文章

【进阶篇】Redis内存淘汰详解

文章目录 Redis内存淘汰详解0. 前言大纲Redis内存淘汰策略 1. 什么是Redis内存淘汰策略&#xff1f;1.1.Redis 内存不足的迹象 2. Redis内存淘汰策略3. 原理4. 主动和被动1. 主动淘汰1.1 键的生存周期1.2 过期键删除策略 2. 被动淘汰2.2 被动淘汰策略的实现 5. 项目实践优化策略…

Android 播放mp3文件

1&#xff0c;在res/raw中加入mp3文件 2&#xff0c;实现播放类 import android.content.Context; import android.media.AudioManager; import android.media.SoundPool; import android.util.Log;import java.util.HashMap; import java.util.Map;public class UtilSound {pu…

C#__资源访问冲突和死锁问题

/// 线程的资源访问冲突&#xff1a;多个线程同时申请一个资源&#xff0c;造成读写错乱。 /// 解决方案&#xff1a;上锁&#xff0c;lock{执行的程序段}:同一时刻&#xff0c;只允许一个线程访问该程序段。 /// 死锁问题&#xff1a; /// 程序中的锁过多&#xf…

vue+elementUI el-select 自定义搜索逻辑(filter-method)

下拉列表的默认搜索是搜索label显示label,我司要求输入id显示label名称 <el-form-item label"部门&#xff1a;"><el-select v-model"form.region1" placeholder"请选择部门" filterable clearable:filter-method"dataFilter&qu…

PHP对接阿里云虚拟号的实现(号码隐私保护)

fastadmin 封装框架 实现功能&#xff1a;AXN隐私号绑定、解绑&#xff1b; 场景&#xff1a;为店铺手机号开通虚拟号&#xff0c;用户联系店铺展示虚拟号码&#xff1b; 官方开放文档地址&#xff1a;https://help.aliyun.com/document_detail/59655.html?spma2c4g.111742…

9月7日上课内容 redis群集

redis高可用重点回顾 redis的两种持久化方式 rdb 优缺点 缺点 ① 数据完整性不如AOF ② RDB类似于快照&#xff08;完备&#xff09; ③ 在进行备份时会阻塞进程 优点 ① 持久化的速度比较快&#xff08;因为保存的是数据结果&#xff09;&#xff0c;在写入到*.rdb持久化文…

[docker]笔记-存储管理

1、docker数据存储分为非永久性存储和永久性存储。 非永久性存储&#xff1a;容器创建会默认创建非永久性存储&#xff0c;该存储从属于容器&#xff0c;生命周期与容器相同&#xff0c;会随着容器的关闭而消失&#xff08;可理解为内存中数据&#xff0c;会随关机而消失&…

MySQL——笔试测试题

解析&#xff1a; 要查询各科目的最大分数&#xff0c;可以使用如下的SQL语句&#xff1a; SELECT coursename, MAX(score) FROM t_stuscore GROUP BY coursename; 这条SQL语句使用了MAX()聚合函数来获取每个科目的最大分数&#xff0c;并使用GROUP BY子句按照科目进行分组…

保留网络[02/3]:大型语言模型转换器的继任者”

一、说明 在这项工作中&#xff0c;我们提出保留网络&#xff08;RETNET&#xff09;作为基础架构大型语言模型的结构&#xff0c;同时实现训练并行&#xff0c; 推理成本低&#xff0c;性能好。我们从理论上推导出这种联系 复发与关注之间。然后我们提出保留机制 序列建模&…

时间旅行的Bug 奇怪的输入Bug

故事一&#xff1a;时间旅行的Bug 在一个普通的工作日&#xff0c;程序员小明正在开发一个时间旅行的应用程序。这个应用程序可以让用户选择一个特定的日期和时间&#xff0c;然后将用户的意识传送到过去或未来的那个时刻。小明对这个项目非常兴奋&#xff0c;他认为这将是一个…

微信小程序中 vant weapp 使用外部的icon作为图标的步骤

微信小程序中 vant weapp 使用外部的icon作为图标的步骤 1. 在项目中创建静态资源文件夹2. 前往iconfont图标官网&#xff0c;添加图标并拷贝在线链接3. 下载iconfont代码&#xff0c;解压之后拷贝到小程序的目录中4. 修改iconfont.wxss 将本地链接替换为在线链接5. 在项目的ap…

RLAIF:一个不依赖人工的RLHF替代方案

深度学习自然语言处理 原创作者&#xff1a;Winnie LLM可以标记人类偏好数据&#xff0c;用于强化学习吗&#xff1f;尽管之前有一些类似的研究&#xff0c;但从没有人系统地对比RLHF和RLAIF的性能。今天&#xff0c;我们为大家带来一项Google最新的研究&#xff0c;来看看LLM是…