数据结构与算法基础篇--栈

栈(Stack)是一种重要的数据结构,它遵循“先进后出”(LIFO, Last In, First Out)的原则。栈是一种抽象数据类型,意味着它定义了数据的操作而不具体指定如何实现。栈可以通过不同的数据结构来实现,例如数组或链表

1. 基本概念

LIFO(Last In, First Out):栈遵循先进后出原则,即最后添加的元素最先被移除。例如,想象一个堆叠的盘子,最后放上去的盘子会最先被取走。

操作:

入栈(Push):将元素添加到栈的顶端。
出栈(Pop):从栈的顶端移除并返回元素。
查看栈顶元素(Peek/Top):查看栈顶的元素但不移除它。
检查栈是否为空(isEmpty):判断栈是否为空,即没有元素。

2. 栈的应用

函数调用管理:程序在调用函数时,会将函数的执行状态保存到栈中,这样函数执行完毕后,可以恢复到调用点继续执行。这是栈在编程中的一个重要应用。

撤销操作:在文本编辑器或图形软件中,撤销操作通常使用栈来管理用户的操作历史。

表达式求值:栈可以用来计算后缀表达式(逆波兰表示法)和处理中缀表达式的运算符优先级。

回溯算法:在解决复杂问题时,栈用于回溯算法来记录每一步的状态,以便可以在遇到问题时回到先前的状态。

3. 栈的实现

栈可以通过不同的数据结构实现,常见的实现方法有:

数组实现:
优点:操作简单,访问元素速度快。
缺点:固定大小,可能浪费内存或需要重新分配空间。

链表实现:
优点:动态大小,可以有效利用内存。
缺点:相较于数组,访问元素速度稍慢,需要额外的空间来存储指针。基于数组的实现栈

package com.rojer.pri;

import java.util.EmptyStackException;

/**
 * 基于数组实现的栈
 */
public class StackUsingArray {
    // 实际存储数组
    private final Object[] stack;
    // 栈帧
    private int top;
    // size
    private final int capacity;

    // 构造函数定长
    public StackUsingArray(int size) {
        capacity = size;
        stack = new Object[capacity];
        top = -1;
    }

    // 添加元素到栈帧
    public void push(int value) {
        if (top == capacity - 1) {
            throw new StackOverflowError("Stack is full");
        }
        stack[++top] = value;
    }

    // 取出栈帧
    public Object pop() {
        if (isEmpty()) {
            throw new EmptyStackException();
        }
        return stack[top--];
    }

    // 获取栈帧
    public Object peek() {
        if (isEmpty()) {
            throw new EmptyStackException();
        }
        return stack[top];
    }

    // 判断空
    public boolean isEmpty() {
        return top == -1;
    }

    public static void main(String[] args) {
        StackUsingArray stack = new StackUsingArray(5);

        stack.push(10);
        stack.push(20);
        stack.push(30);

        System.out.println("Top element: " + stack.peek()); // Output: 30
        System.out.println("Popped element: " + stack.pop()); // Output: 30
        System.out.println("Top element after pop: " + stack.peek()); // Output: 20

        StackUsingArray stack1 = new StackUsingArray(3);

        stack1.push(11);
        stack1.push(22);
        stack1.push(33);

        System.out.println("Top element: " + stack1.peek()); // Output: 30
        System.out.println("Popped element: " + stack1.pop()); // Output: 30
        System.out.println("Top element after pop: " + stack1.peek()); // Output: 20
    }
}

基于链表实现的栈

package com.rojer.pri;

import java.util.EmptyStackException;
import java.util.LinkedList;

public class StackUsingLinkedList {
    private LinkedList<Integer> stack = new LinkedList<>();

    public void push(int value) {
        stack.addFirst(value);
    }

    public int pop() {
        if (isEmpty()) {
            throw new EmptyStackException();
        }
        return stack.removeFirst();
    }

    public int peek() {
        if (isEmpty()) {
            throw new EmptyStackException();
        }
        return stack.getFirst();
    }

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

    public static void main(String[] args) {
        StackUsingLinkedList stack = new StackUsingLinkedList();

        stack.push(10);
        stack.push(20);
        stack.push(30);

        System.out.println("Top element: " + stack.peek()); // Output: 30
        System.out.println("Popped element: " + stack.pop()); // Output: 30
        System.out.println("Top element after pop: " + stack.peek()); // Output: 20
    }
}

4. 优缺点

优点:

简单性:栈是一种简单而直观的数据结构,易于实现和理解。
高效:栈的基本操作(入栈、出栈、查看栈顶)都是常数时间复杂度 O(1)。
灵活性:栈可以用在各种算法和数据处理中,如深度优先搜索、递归等。

缺点:

单向访问:栈只允许从一端进行操作,不支持随机访问或在中间进行操作。
内存限制:在使用数组实现时,栈的容量是固定的,可能导致栈溢出或内存浪费。

5,常用jdk的栈的实现类

Stack
  • java.util.Stack 是一个直接实现了栈的类,它继承自 Vector 类并实现了 List 接口。这个类提供了常见的栈操作,如 push()、pop()、peek()、empty() 和 search()。
  • 由于 Stack 继承自 Vector,它是同步的,但它不建议在高并发环境下使用,效率较低。
ArrayDeque
  • ArrayDeque 是 Deque 接口的一个实现,通常用来实现栈和队列。它提供了无界的双端队列,并且比 Stack 类更高效。
  • 使用 ArrayDeque 实现栈可以通过 push()、pop() 和 peek() 方法来完成。
LinkedList
  • LinkedList 也是 Deque 接口的一个实现,同样可以用来实现栈和队列。它基于链表结构,适用于需要频繁插入和删除元素的场景。
  • 使用 LinkedList 实现栈同样可以通过 push()、pop() 和 peek() 方法来完成。

6,leetcode中相关题目

简单难度

20,155,232,255,1021,1047

中等难度

739,496,150,503,946

困难

32

  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值