沉梦听雨的编程指南 沉梦听雨的编程指南
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)

沉梦听雨

时间是最好的浸渍剂,而沉淀是最好的提纯器🚀
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)
  • 网络

  • 操作系统

  • 数据结构与算法

    • 数据结构基础小结
    • 基础篇

      • 学前须知
      • 复杂度
      • 动态数组
      • 链表
      • 栈
        • 简介
        • 接口设计
        • 代码实现
        • 栈的应用举例
        • 练习
          • 20.有效的括号
          • 解法一
          • 解法二
          • 解法三
          • 856.括号的方数
          • 36.逆波兰表达式求值
          • 224.基本计算器
      • 队列
      • 二叉树
      • 二叉搜索树
      • AVL树
      • B树
      • 红黑树
      • 集合
      • 映射
      • 哈希表
      • 二叉堆
      • 优先级队列
      • 哈夫曼树
      • Tire
      • 总结
    • 力扣篇

  • 计算机基础
  • 数据结构与算法
  • 基础篇
沉梦听雨
2023-09-28
目录

栈

# 栈

# 简介

栈是一种特殊的线性表,只能在一端进行操作

  • 往栈中添加元素的操作,一般叫做 push,入栈
  • 从栈中移除元素的操作,一般叫做 pop,出栈(只能移除栈顶元素,也叫做: 弹出栈顶元素)
  • 后进先出的原则,Last In First Out,LIFO

# 接口设计

一般设计以下几种接口,添加删除操作都是 O(1) 级别

image

返回栈底元素:top() 相当于官方的 peek()

# 代码实现

内部实现可利用到之前学习的数据结构:动态数组,链表

public class Stack<E> {
  
	private List<E> list = new ArrayList<>();
	
	public void clear() {
		list.clear();
	}
	
	public int size() {
		return list.size();
	}

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

	public void push(E element) {
		list.add(element); // 相当于在数组尾部添加元素
	}

	public E pop() {
		return list.remove(list.size() - 1); // 相当于在数组尾部删除元素,并返回被删除的元素
	}

	public E top() {
		return list.get(list.size() - 1);
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

接口测试

public class Main {

	public static void main(String[] args) {
		Stack<Integer> stack = new Stack<>();
		stack.push(11);
		stack.push(22);
		stack.push(33);
		stack.push(44);

		while (!stack.isEmpty()) {
			System.out.println(stack.pop());
		}
	}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

可查看官方实现

java.util.Stack<Integer> stack;
1

# 栈的应用举例

1、浏览器的前进和后退(应用到两个栈)

2、软件的撤销(Undo)、恢复(Redo)功能

具体解析

后退:

后退操作:第一个栈的栈顶元素被弹出(pop),进入第二个栈(push)

image

前进:

前进操作:第二个栈的元素被弹出(pop),进入第一个栈(push)

image

输入新网址:

新网址进入第一个栈(push),第二个栈保存的元素被清空(clear)

image

# 练习

# 20.有效的括号

官方地址:20. 有效的括号 - 力扣(LeetCode) (opens new window)

# 解法一

用 空字符串替换 的方法

class Solution {
    public boolean isValid(String s) {

        while(s.contains("()") || s.contains("{}") || s.contains("[]")) {
            s = s.replace("()", "");
            s = s.replace("{}", "");
            s = s.replace("[]", "");
        }
        return s.isEmpty();

    }
}
1
2
3
4
5
6
7
8
9
10
11
12

缺点:

效率非常低,耗内存。

原因:

字符串的查找操作跟字符串的替换操作都是非常耗性能的,而且字符串是不可变的。字符串不可变,它就会不断地去产生新的字符串,这样会浪费内存,而且效率特别低。

# 解法二

用 栈 方法

class Solution {
    public boolean isValid(String s) {

        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == '(' || c == '{' || c == '[') { // 左括号
                stack.push(c); // 入栈
            } else { // 右括号
                if (stack.isEmpty()) return false;

                char left = stack.pop(); // 出栈
                if (left == '(' && c != ')') return false;
                if (left == '{' && c != '}') return false;
                if (left == '[' && c != ']') return false;

            }
        }
        return stack.isEmpty();

    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 解法三

用 Map(字典)+ 栈 的方法。

class Solution {

    private static final HashMap<Character, Character> map = new HashMap<>();
    static {
        map.put('(',')');
        map.put('{','}');
        map.put('[',']');
    }

    public boolean isValid(String s) {

        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (map.containsKey(c)) {
                stack.push(c);
            } else {
                if (stack.isEmpty()) return false;

                char left = stack.pop();
                if (c != map.get(left)) return false;
            }
        }
        return stack.isEmpty();

    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 856.括号的方数

官方地址:856. 括号的分数 - 力扣(LeetCode) (opens new window)

# 36.逆波兰表达式求值

官方地址:LCR 036. 逆波兰表达式求值 - 力扣(LeetCode) (opens new window)

# 224.基本计算器

官方地址:224. 基本计算器 - 力扣(LeetCode) (opens new window)

上次更新: 2024/9/25 11:16:13
链表
队列

← 链表 队列→

Theme by Vdoing | Copyright © 2023-2025 沉梦听雨 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式