数据结构与算法-栈

链表实现

java 复制代码
public class LinkedListStack<E> {

    // 内部类:链表节点
    static class Node<E> {
        E value;       // 节点存储的值
        Node<E> next;  // 指向下一个节点的引用

        // 构造函数:初始化节点
        public Node(E value, Node<E> next) {
            this.value = value;
            this.next = next;
        }
    }

    // 栈的最大容量
    private final int capacity;
    // 栈中元素的数量
    private int size;
    // 头节点,始终指向栈顶元素的前一个节点(即哨兵节点)
    private final Node<E> head = new Node<>(null, null);

    /**
     * 构造函数:初始化栈。
     *
     * @param capacity 栈的容量
     */
    public LinkedListStack(int capacity) {
        this.capacity = capacity;
    }

    /**
     * 向栈中添加一个元素。
     *
     * @param value 要添加的元素
     * @return 如果成功添加返回 true;如果栈已满返回 false
     */
    public boolean push(E value) {
        if (isFull()) {
            return false;
        }
        // 将新元素插入到头节点之后
        head.next = new Node<>(value, head.next);
        size++;
        return true;
    }

    /**
     * 从栈中移除并返回栈顶元素。
     *
     * @return 栈顶元素;如果栈为空返回 null
     */
    public E pop() {
        if (isEmpty()) {
            return null;
        }
        // 获取栈顶元素
        Node<E> first = head.next;
        // 更新头节点的 next 指针,跳过栈顶元素
        head.next = first.next;
        size--;
        return first.value;
    }

    /**
     * 返回栈顶元素但不移除它。
     *
     * @return 栈顶元素;如果栈为空返回 null
     */
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return head.next.value;
    }

    /**
     * 判断栈是否为空。
     *
     * @return 如果栈为空返回 true,否则返回 false
     */
    public boolean isEmpty() {
        return head.next == null;
    }

    /**
     * 判断栈是否已满。
     *
     * @return 如果栈已满返回 true,否则返回 false
     */
    public boolean isFull() {
        return size == capacity;
    }
}

数组实现

java 复制代码
public class ArrayStack<E> {
    // 使用泛型数组存储栈中的元素
    private final E[] array;
    // 栈顶指针,初始化为0,指向下一个要插入元素的位置
    private int top = 0;

    // 构造函数,初始化栈的容量
    @SuppressWarnings("unchecked") // 抑制编译器关于类型转换的警告
    public ArrayStack(int capacity) {
        // 创建指定容量的Object数组并强制转换为E类型数组
        this.array = (E[]) new Object[capacity];
    }

    /**
     * 将元素压入栈中。
     * 如果栈已满,则返回false表示失败;否则将元素加入栈并返回true。
     */
    public boolean push(E value) {
        if (isFull()) { // 检查栈是否已满
            return false;
        }
        array[top] = value; // 放置元素到当前栈顶位置
        top++; // 增加栈顶指针
        return true;
    }

    /**
     * 弹出栈顶元素。
     * 如果栈为空,则返回null;否则移除并返回栈顶元素。
     */
    public E pop() {
        if (isEmpty()) { // 检查栈是否为空
            return null;
        }
        top--; // 减少栈顶指针,指向新的栈顶
        return array[top]; // 返回被移除的栈顶元素
    }

    /**
     * 查看栈顶元素但不移除它。
     * 如果栈为空,则返回null;否则返回栈顶元素。
     */
    public E peek() {
        if (isEmpty()) { // 检查栈是否为空
            return null;
        }
        return array[top - 1]; // 返回栈顶元素
    }

    /**
     * 判断栈是否为空。
     * 如果栈顶指针为0,则栈为空。
     */
    public boolean isEmpty() {
        return top == 0;
    }

    /**
     * 判断栈是否已满。
     * 如果栈顶指针等于数组长度,则栈已满。
     */
    public boolean isFull() {
        return top == array.length;
    }
}

有效的括号-Leetcode 20

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

**输入:**s = "()"

**输出:**true

示例 2:

**输入:**s = "()[]{}"

**输出:**true

示例 3:

**输入:**s = "(]"

**输出:**false

示例 4:

**输入:**s = "([])"

**输出:**true

java 复制代码
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();
	}
public class ArrayStack<E>{
		 private final E[] array;
		    private int top = 0;

		    @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;
		    }
	}
}

逆波兰表达式求值-Leetcode 150

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*''/'
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

示例 1:

复制代码
输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

复制代码
输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

示例 3:

复制代码
输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
java 复制代码
public int evalRPN(String[] tokens) {
		 Deque<Integer> numbers = new LinkedList<Integer>();
		 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();
		 }

拓:中缀表达式转后缀

java 复制代码
 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);
        };
    }

双栈模拟队列-Leetcode 232

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 只能 使用标准的栈操作 ------ 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

示例 1:

复制代码
输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
java 复制代码
class MyQueue {

    Deque<Integer> s1;
	Deque<Integer> s2;
	 public MyQueue() {
		s1 = new  ArrayDeque<Integer>(100);
		s2 = new  ArrayDeque<Integer>(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();
	        
	    }
}

单队列模拟栈-Leetcode 225

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppopempty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false

注意:

  • 你只能使用队列的标准操作 ------ 也就是 push to backpeek/pop from frontsizeis empty 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

复制代码
输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]

解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False
java 复制代码
public class MyStack {
	Queue<Integer> queue;
	int size=0;
	MyStack() {
        queue= new LinkedList<Integer>();
        
    }
    
    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();
    }
}
相关推荐
Seven972 分钟前
【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
java·后端·设计模式
matrixlzp5 分钟前
Java 生成图形验证码
java·spring
冰淇淋@6 分钟前
HTTP发送POST请求的两种方式
java·spring boot·http
不爱学习的小枫19 分钟前
scala的集合
开发语言·scala
梦醒沉醉20 分钟前
Scala的初步使用
开发语言·后端·scala
codingPower21 分钟前
IDEA接入阿里云百炼中免费的通义千问[2025版]
java·阿里云·intellij-idea
小白学大数据25 分钟前
Fuel 爬虫:Scala 中的图片数据采集与分析
开发语言·爬虫·scala
贩卖纯净水.39 分钟前
《React 属性与状态江湖:从验证到表单受控的实战探险》
开发语言·前端·javascript·react.js
JouJz44 分钟前
Java基础系列:深入解析反射机制与代理模式及避坑指南
java·开发语言·代理模式
小安同学iter1 小时前
Spring(七)AOP-代理模式
java·后端·spring