6、栈

一、什么是栈

   栈(Stack)是一种基础且重要的数据结构,它在计算机科学和软件开发中有着广泛的应用。栈是一个遵循“后进先出”(Last In First Out, LIFO;类似于弹匣)原则的线性表,这意味着最后被压入栈中的元素将是第一个被弹出的元素。

二、栈能做什么

1、函数调用栈(Call Stack):

  • 在程序执行过程中,每当一个函数被调用时,其局部变量、返回地址等信息会被压入栈中形成一个栈帧,用于保存函数运行状态。当函数执行完毕时,相应的栈帧从栈顶弹出,程序控制权返回到上一级调用。

2、表达式求值与计算:

  • 栈可以用来辅助计算逆波兰表示法(Reverse Polish Notation,RPN)等非传统格式的数学表达式。
  • 也可以用于括号匹配问题,如检查字符串中的括号是否正确嵌套。

3、深度优先搜索(DFS):

  • 在图或树的遍历算法中,栈用于实现深度优先搜索策略,通过不断将下一个待访问节点压入栈来决定搜索顺序。

4、数制转换:

  • 进制转换(例如十进制转二进制、八进制或十六进制)可以通过反复除以目标基数并把余数压入栈来完成,最后栈中的元素序列即为目标进制下的数字。

5、内存管理:

  • 在某些内存分配方案中,栈可用于为函数自动分配和释放本地内存空间。

6、操作系统任务调度:

  • 操作系统内核可能会使用栈来维护进程或线程的上下文切换信息。

7、回溯算法:

  • 在解决一些组合优化问题时,栈常常作为临时存储路径的一部分,帮助算法在尝试失败时快速恢复到之前的决策点。

8、递归函数的实现:

  • 虽然递归本身不是直接依赖于栈,但在编译器内部处理递归调用时会利用栈来保存递归层级的信息。

总之,栈是一种灵活且高效的工具,它的特点是操作简单且符合很多编程场景对“后进先出”逻辑的需求。

三、实现方式

  栈可以通过两种主要的方式来实现:顺序存储(数组)和 链式存储(链表)。

1、数组

  • 在数组中,栈的元素从固定的一端(通常是数组的末尾)进行插入和删除。
  • 初始化一个固定大小或动态可扩展的数组。
  • 定义一个变量 top 来表示栈顶的位置。当栈为空时,top 为 -1 或者指向数组的第一个位置之外;随着元素入栈,top 向后移动一位;出栈时,top 回退一位。
  • 数组实现的优点是访问速度快,由于只在一端操作,入栈和出栈的时间复杂度通常为 O(1)。
  • 缺点是在预先分配的空间用完后需要扩容,扩容操作可能涉及到数据迁移,效率相对较低,并且可能会造成一定的空间浪费。

2、链表

  • 使用单链表作为底层结构,栈底可以看作是链表的尾部,而栈顶则是链表头部。
  • 新元素入栈时,在链表头部添加新的节点。
  • 出栈时,只需删除链表的头部节点即可。
  • 链表实现的优点是可以灵活地扩展栈的容量,无需预先确定栈的大小,而且不会遇到数组扩容的问题。
  • 缺点是相比于数组,链表的插入和删除操作虽然也是 O(1),但通常涉及指针操作,因此在实际运行时可能会有额外的开销。

四、代码案例

1、定义一个公共接口

package 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 返回个数
     */
    int size();

    /**
     * 判断栈是否已满
     * @return 满返回 true, 否则返回 false
     */
    boolean isFull();
}

2、数组实现案例

package stack;

/**
 * 数组实现栈
 *
 * @param <E>
 */
public class ArrayStack<E> implements Stack {

    //数组栈
    private final E[] array;

    //top
    private int top = 0;

    //栈内元素的数量
    private int size = 0;

    public ArrayStack(int length) {
        this.array = (E[]) new Object[length];
    }

    /**
     * 入栈:将一个元素添加到栈顶。
     *
     * @param value 值
     * @return
     */
    @Override
    public boolean push(Object value) {
        //判断栈是否已满
        if (isFull()) {
            return false;
        }
        array[top] = (E) value;
        top++;
        size++;
        return true;
    }

    /**
     * 出栈:移除并返回栈顶的元素。
     *
     * @return 栈非空返回栈顶元素, 栈为空返回 null
     */
    @Override
    public Object pop() {
        //判断数组是否为空。
        if (isEmpty()) {
            return null;
        }
        E data = array[top - 1];
        array[top - 1] = null;//清空出栈的元素,垃圾回收
        top--;
        size--;
        return data;
    }

    /**
     * 查看栈顶元素:不移除栈顶元素的情况下查看其值。
     *
     * @return 栈非空返回栈顶元素, 栈为空返回 null
     */
    @Override
    public Object peek() {
        //判断数组是否为空。
        if (isEmpty()) {
            return null;
        }
        E data = array[top - 1];
        return data;
    }

    /**
     * 判断是否为空栈:检查栈中是否包含元素。
     *
     * @return 空返回 true, 否则返回 false
     */
    @Override
    public boolean isEmpty() {
        return top == 0;
    }

    /**
     * 获取栈大小:获取栈内元素的数量。
     *
     * @return 返回个数
     */
    @Override
    public int size() {
        return size;
    }

    /**
     * 判断栈是否已满
     *
     * @return 满返回 true, 否则返回 false
     */
    @Override
    public boolean isFull() {
        return size == array.length;
    }

    //返回队列中的内容
    public E[] getArray() {
        return array;
    }
}

在这里插入图片描述

3、链表实现案例

 package stack;

public class LinkedListStack<E> implements Stack {

    //栈的长度
    private int length;

    //栈内元素的数量
    private int size;

    private Node head;

    public LinkedListStack(int length) {
        this.length = length;
        this.size = 0;
        this.head = new Node(null, null);
    }

    class Node {
        E value;
        Node next;

        public Node(E value, Node node) {
            this.value = value;
            this.next = node;
        }
    }

    /**
     * 入栈:将一个元素添加到栈顶。
     *
     * @param value 值
     * @return 压入成功返回 true, 否则返回 false
     */
    @Override
    public boolean push(Object value) {
        //判断栈是否已满
        if (isFull()) {
            return false;
        }
        head.next = new Node((E) value, head.next);
        size++;
        return true;
    }

    /**
     * 出栈:移除并返回栈顶的元素。
     *
     * @return 栈非空返回栈顶元素, 栈为空返回 null
     */
    @Override
    public Object pop() {
        if (isEmpty()) {
            return null;
        }
        Node data = head.next;
        head.next = data.next;
        size--;
        return data.value;
    }

    /**
     * 查看栈顶元素:不移除栈顶元素的情况下查看其值。
     *
     * @return 栈非空返回栈顶元素, 栈为空返回 null
     */
    @Override
    public Object peek() {
        if (isEmpty()) {
            return null;
        }
        return head.next.value;
    }

    /**
     * 判断是否为空栈:检查栈中是否包含元素。
     *
     * @return 空返回 true, 否则返回 false
     */
    @Override
    public boolean isEmpty() {
        return head.next == null;
    }

    /**
     * 获取栈大小:获取栈内元素的数量。
     *
     * @return 返回个数
     */
    @Override
    public int size() {
        return size;
    }

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

  • 17
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值