栈简介 Stack

栈的本质

栈也是一种数据呈线性排列的数据结构,不过在这种结构中,我们只能访问最新添加的数据。

⨳ 栈就像是一摞书,拿到新书时我们会把它放在书堆的最上面,取书时也只能从最上面的新书开始取。

⨳ 栈也像一摞叠在一起的盘子,我们平时放盘子的时候,都是从下往上一个一个放;取的时候,我们也是从上往下一个一个地依次取,不能从中间任意抽出。

⨳ 栈也像子弹夹,子弹夹只有一个口,最新压入的子弹,也是最开始射出的子弹。

总之,后进者先出(Last In First Out,简称 LIFO),就是典型的"栈"结构。

前文讲了数组和链表这两种不同的线性存储结构,而栈既可以用数组实现(顺序栈 ),也可以用链表实现(链式栈)。

栈主要 API 如下:

⨳ void push(E):入栈操作,向栈顶添加元素

⨳ E pop():出栈操作,从栈顶弹出元素

⨳ E peek():查看栈顶元素

相比数组和链表,栈就是个阉割版本,那我直接使用数组或者链表不就好了吗?为什么还要用这个"操作受限"的"栈"呢?

因为数组或链表暴露了太多的操作接口,操作上的确灵活自由,但使用时就比较不可控,比较容易出错(单一职责)。

下面就分别使用数组和链表实现一个栈。

顺序栈 ArrayStack

java 复制代码
import com.cango.array.IntArray; // 数组篇讲的代码

public class IntArrayStack {

    IntArray array ;

    public IntArrayStack(int capacity){
        array = new IntArray(capacity);
    }

    public IntArrayStack(){
        array = new IntArray();
    }


    public void push(int e){
        array.add(array.getSize(),e);
    }


    public int pop(){
        return array.remove(array.getSize()-1);
    }


    public int peek(){
        return array.get(array.getSize()-1);
    }
    
}

看完代码你可能会说,就这?对,将数组操作阉割一下就是栈。

如果 IntArray 支持动态扩容,用 IntArray 实现的栈也会支持动态扩容,多方便。

从上代码可以看出,用数组实现栈最好让数组尾部作为栈顶,因为栈只能操作栈顶的元素,对应到数组,就是只处理数组尾部的元素,不涉及数组其他元素的搬移。

链式栈 LinkedStack

将数组操作阉割一下就是顺序栈,接着将链表阉割一下实现链式栈:

java 复制代码
import com.cango.list.IntList;

public class IntLinkedStack {

    IntList list;

    public IntLinkedStack(){
        list = new IntList();
    }
    
    public void push(int e){
        list.add(0,e);
    }
    
    public int pop(){
        return list.remove(0);
    }
    
    public int peek(){
        return list.get(0);
    }

}

单向链表适合让链表头部作为栈顶,因为链表对头部节点的增删查最快。

Stack VS Deque

scala 复制代码
package java.util;

/**
 * The <code>Stack</code> class represents a last-in-first-out
 * (LIFO) stack of objects. It extends class <tt>Vector</tt> with five
 * operations that allow a vector to be treated as a stack. The usual
 * <tt>push</tt> and <tt>pop</tt> operations are provided, as well as a
 * method to <tt>peek</tt> at the top item on the stack, a method to test
 * for whether the stack is <tt>empty</tt>, and a method to <tt>search</tt>
 * the stack for an item and discover how far it is from the top.
 * <p>
 * When a stack is first created, it contains no items.
 *
 * <p>A more complete and consistent set of LIFO stack operations is
 * provided by the {@link Deque} interface and its implementations, which
 * should be used in preference to this class.  For example:
 * <pre>   {@code
 *   Deque<Integer> stack = new ArrayDeque<Integer>();}</pre>
 *
 * @author  Jonathan Payne
 * @since   JDK1.0
 */
public
class Stack<E> extends Vector<E>

这是 Java 版本的 Stack,从描述上看,官方推荐使用 Deque 代替 Stack 。

为啥呢?

Stack 类对 push、pop 方法实现很好呀,原因就是它是继承 Vector ,而不是组合 Vector (Vector 是个线程安全的数组封装),这就导致 Stack 不仅仅有 push、pop 方法,数组相关操作方法都有,Stack 存在的意义就是屏蔽多余的操作,现在 Stack 操作这么多,怎能不让开发者迷惑。

Java 官方推荐的写法是使用 Deque 接口:

java 复制代码
 Deque<Integer> stack = new ArrayDeque<Integer>();}

Deque 是双端队列的意思,也就是说可以在队列两头操作元素,那我只用一头进行插入和删除,这不就是栈了嘛。

Deque 还是暴露了多余的操作呀,是的,哪能这么办,重新构造 Stack 类吗?原来的项目怎么办?

妥协的方法就是,选择一个比较符合栈操作的类,也就是 Deque。

相关推荐
这个昵称不容易1 小时前
SpringBoot「衣依」服装销售平台:144个Java文件180个接口,从挑衣服到收货评价整条链路都在
java·springboot·毕设
计算机毕设定制辅导-无忧学长2 小时前
《基于微信小程序的居家医疗陪护预约系统设计与实现》
java·spring boot·微信小程序·uniapp·居家医疗陪护预约系统
文丑颜不良啊3 小时前
LeetCode2221~2240题目解析
java·leetcode
秋饼3 小时前
Computer Use Agent Java 落地实战:感知-行动循环、执行器与安全围栏生产级实现
java·ai·技术分享·后端开发
Navigator_Z3 小时前
LeetCode //C - 1317. Convert Integer to the Sum of Two No-Zero Integers
c语言·算法·leetcode
D e re k ZH4 小时前
C++ 标准库算法全景指南
数据结构·c++·算法
冻柠檬飞冰走茶5 小时前
字母移动游戏题解:贪心求最长可保留连续子串(附 C 实现)
c语言·开发语言·数据结构·算法·动态规划
文丑颜不良啊5 小时前
LeetCode2161~2180题目解析
java·leetcode
雪落漂泊5 小时前
C++算法 二分查找篇(上)
开发语言·c++·算法