数据结构之栈:原理与常用方法

1. 栈的定义

Stack是Vector的一个子类,它实现标准的后进先出堆栈。Stack只定义了创建空堆栈的默认构造方法。(实际上是实现了List接口,因为Vector是List的子类)。

Stack() // 创建一个空栈

2. 栈的基本操作

// 压栈操作
public E push(E item) // 将元素压入栈顶
 
// 弹栈操作
public E pop() // 移除栈顶元素并返回该元素
 
// 查看栈顶元素但不移除
public E peek() // 查看栈顶元素但不移除
 
// 判断栈是否为空
public boolean empty() // 测试栈是否为空
 
// 查找元素在栈中的位置(从栈顶开始为1)
public int search(Object o) // 返回对象在栈中的位置,1表示栈顶

3. 继承自Vector的方法

由于Stack继承自Vector,所以还拥有以下方法:

// 获取栈的大小
public int size() 

// 判断栈是否包含指定元素
public boolean contains(Object o)

// 返回指定位置的元素
public E get(int index)

// 清空栈
public void clear()

4. Java 中的 Stack 类

Java 提供了一个内置的 Stack 类,它扩展了 Vector 类。尽管 Stack 类仍然可用,但在现代 Java 编程中,通常推荐使用 Deque 接口的实现(如 ArrayDeque )来模拟栈的行为。

  • 由于Stack继承自Vector,所有方法都是同步的,这在多线程环境下是安全的,但在单线程环境下会有性能损失。
  • Deque接口提供了更完整的栈操作,性能更好(非同步实现)

4.1. 使用 Java 的 Stack 类

import java.util.Stack;

public class StackExample {
    public static void main(String[] args) {
        Stack<String> stack = new Stack<>();
        
        // 压栈操作
        stack.push("Apple");
        stack.push("Banana");
        stack.push("Cherry");
        
        // 查看栈大小
        System.out.println("Stack size: " + stack.size()); // 输出: 3
        
        // 查看栈顶元素
        System.out.println("Top element: " + stack.peek()); // 输出: Cherry
        
        // 弹栈操作
        System.out.println("Popped: " + stack.pop()); // 输出: Cherry
        System.out.println("Popped: " + stack.pop()); // 输出: Banana
        
        // 判断栈是否为空
        System.out.println("Is stack empty? " + stack.empty()); // 输出: false
        
        // 查找元素位置
        System.out.println("Apple position: " + stack.search("Apple")); // 输出: 1
        
        // 清空栈
        stack.clear();
        System.out.println("Is stack empty after clear? " + stack.empty()); // 输出: true
    }
}
 

4.2. 使用 Deque 接口实现栈

import java.util.ArrayDeque;
import java.util.Deque;

public class DequeAsStackExample {
    public static void main(String[] args) {
        Deque<String> stack = new ArrayDeque<>();

        // 压栈
        stack.push("Apple");
        stack.push("Banana");
        stack.push("Cherry");

        System.out.println("Stack: " + stack);

        // 出栈
        String top = stack.pop();
        System.out.println("Popped element: " + top);

        // 查看
        System.out.println("Top element: " + stack.peek());

        System.out.println("Updated stack: " + stack);

        // 判空
        System.out.println("Is stack empty? " + stack.isEmpty());
    }
}

5. 实现自定义栈

我们可以使用数组或链表来实现自定义栈。以下是使用数组实现的简单栈:

public class ArrayStack<T> {
    private T[] array;
    private int top;
    private int capacity;

    @SuppressWarnings("unchecked")
    public ArrayStack(int capacity) {
        this.capacity = capacity;
        array = (T[]) new Object[capacity];
        top = -1;
    }

    public void push(T item) {
        if (isFull()) {
            throw new IllegalStateException("Stack is full");
        }
        array[++top] = item;
    }

    public T pop() {
        if (isEmpty()) {
            throw new IllegalStateException("Stack is empty");
        }
        return array[top--];
    }

    public T peek() {
        if (isEmpty()) {
            throw new IllegalStateException("Stack is empty");
        }
        return array[top];
    }

    public boolean isEmpty() {
        return top == -1;
    }

    public boolean isFull() {
        return top == capacity - 1;
    }
}

6. 栈的应用

栈在计算机科学和日常编程中有广泛的应用,例如:

  1. 函数调用和递归
  2. 表达式求值和语法解析
  3. 撤销操作(Undo)
  4. 深度优先搜索(DFS)算法
  5. 括号匹配问题

7. 栈的实际应用示例

7.1. 括号匹配

public static boolean isBalanced(String expression) {
    Stack<Character> stack = new Stack<>();
    for (char ch : expression.toCharArray()) {
        if (ch == '(' || ch == '[' || ch == '{') {
            stack.push(ch);
        } else if (ch == ')' || ch == ']' || ch == '}') {
            if (stack.isEmpty()) {
                return false;
            }
            char top = stack.pop();
            if ((ch == ')' && top != '(') || 
                (ch == ']' && top != '[') || 
                (ch == '}' && top != '{')) {
                return false;
            }
        }
    }
    return stack.isEmpty();
}

7.2. 逆波兰表达式求值

public static int evaluateRPN(String[] tokens) {
    Stack<Integer> stack = new Stack<>();
    for (String token : tokens) {
        if (token.equals("+") || token.equals("-") || 
            token.equals("*") || token.equals("/")) {
            int b = stack.pop();
            int a = stack.pop();
            switch (token) {
                case "+": stack.push(a + b); break;
                case "-": stack.push(a - b); break;
                case "*": stack.push(a * b); break;
                case "/": stack.push(a / b); break;
            }
        } else {
            stack.push(Integer.parseInt(token));
        }
    }
    return stack.pop();
}

8. 栈的优缺点

优点:

  • 实现简单
  • 后进先出的特性适用于许多算法和问题解决
  • 函数调用和递归的基础

缺点:

  • 只能访问最顶端的元素
  • 不支持随机访问
  • 大小通常是固定的(使用数组实现时)

9. 参考资料

Java 数据结构 - 栈(Stack) - KenWan - 博客园

关于的使用,内有关于使用的示例 的应用举例 1. 将10进制正整数num转换为n进制 private String conversion(int num, int n) { MyStack myStack = new MyArrayStack(); Integer result = num; while (true) { // 将余数入 myStack.push(result % n); result = result / n; if (result == 0) { break; } } StringBuilder sb = new StringBuilder(); // 按出的顺序倒序排列即可 while ((result = myStack.pop()) != null) { sb.append(result); } return sb.toString(); } 2. 检验符号是否匹配. '['和']', '('和')'成对出现时字符串合法. 例如"[][]()", "[[([]([])()[])]]"是合法的; "([(])", "[())"是不合法的. 遍历字符串的每一个char, 将char顶元素比较. 如果char和顶元素配对, 则char不入, 否则将char入. 当遍历完成时为空说明字符串是合法的. public boolean isMatch(String str) { MyStack myStack = new MyArrayStack(); char[] arr = str.toCharArray(); for (char c : arr) { Character temp = myStack.pop(); // 为空时只将c入 if (temp == null) { myStack.push(c); } // 配对时c不入 else if (temp == '[' && c == ']') { } // 配对时c不入 else if (temp == '(' && c == ')') { } // 不配对时c入 else { myStack.push(temp); myStack.push(c); } } return myStack.isEmpty(); } 3. 行编辑: 输入行中字符'#'表示退格, '@'表示之前的输入全都无效. 使用保存输入的字符, 如果遇到'#'就将顶出, 如果遇到@就清空. 输入完成时将中所有字符出后反转就是输入的结果: private String lineEdit(String input) { MyStack myStack = new MyArrayStack(); char[] arr = input.toCharArray(); for (char c : arr) { if (c == '#') { myStack.pop(); } else if (c == '@') { myStack.clear(); } else { myStack.push(c); } } StringBuilder sb = new StringBuilder(); Character temp = null; while ((temp = myStack.pop()) != null) { sb.append(temp); } // 反转字符串 sb.reverse(); return sb.toString(); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值