Stack栈结构 及 Java模拟实现

一、导入

不知道大家是否观察过栓动步枪的压弹和击发,无论是压弹还是击发,子弹从弹舱进出有且只有一个出入口,子弹“先进后出,后进先出”,栈就是类似这样弹仓的一种数据存储结构。

二、栈

栈作为一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和数据删除的一端称之为栈顶,另一端则称为栈底。栈中数据元素遵循后进先出原则LIFO(Last In First Out)。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶

上方模型中入栈循序为数据1->数据2->数据3->数据4,通过上方模型可以观察到,对含有4个元素的栈进行出栈操作时,是对位于栈顶的数据4进行删除。而进行入栈操作时,则是将数据4插入栈顶,这时若是再进行出栈操作,则数据4作为栈顶首当其冲的就被删除了,符合“后进先出”原则。

栈的基本结构就是这样,除了入栈、出栈两个基本操作,还有诸如获取栈顶元素但不删除(peek)、获取栈中有效元素个数(size)、检查栈是否为空(empty)等......

三、模拟实现

我们将使用Java来模拟实现栈,在此之前我们要想清楚用什么来充当栈,以及MyStack该实现哪些功能,最后又该如何实现这些功能。

用什么来充当栈?

无论是在栈的介绍中,还是栈模型的构造中,我们都可以观察到栈是一种线性结构,因此从理论上来说线性表,如数组、链表、循序表都可以用来充当栈。

MyStack该实现哪些功能?

基本的入栈、出栈,作为栈的底线,这是必须的。

其他的我们还可以实现:获取栈顶元素但不删除(peek)、获取栈中有效元素个数(size)、检查栈是否为空(empty)。

最后加上一个构造方法,完美。

如何实现?

话不多说,直接上手。

1.使用链表充当栈

        import java.util.LinkedList;

public class MyLinkedStack  extends Exception{
    private LinkedList<Integer> stack;
    private int size;

    //构造方法
    public MyLinkedStack(){
        this.stack = new LinkedList<>();
    }

    //入栈
    public int push(int e){
        if(this.size++ == 0) {
            this.stack.add(e);
            return e;
        }
        this.stack.add(0,e);
        return e;
    }

    //出栈并返回值
    public int pop(){
        if(size()==0) {
            throw new illegalException("无元素");
        }
        this.size--;
        return this.stack.removeFirst();
    }

    //获取栈顶元素
    public int peek(){
        if(size()==0) {
            throw new illegalException("无元素");
        }
        return this.stack.getFirst();
    }

    //返回栈元素个数
    public int size() {
        return this.size;
    }

    //检查站是否为空
    public boolean empty(){
        if(size() == 0) {
            return true;
        }
        return false;
    }
}

测试:

public class Test {
    public static void main(String[] args) {
        MyLinkedStack stack = new MyLinkedStack();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        System.out.println(stack.size());
        System.out.println("=========");
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
    }
}

2.使用数组充当栈

import java.util.Arrays;

public class MyArrayStack {
    int[] array;
    int size;
    public MyArrayStack(){
        array = new int[3];
    }
    public int push(int e){
        ensureCapacity();
        array[size++] = e;
        return e;
    }
    public int pop(){
        int e = peek();
        size--;
        return e;
    }
    public int peek(){
        if(empty()){
            throw new RuntimeException("栈为空,无法获取栈顶元素");
        } 
        return array[size-1];
    }
    public int size(){
        return size;
    }
    public boolean empty(){
        return 0 == size;
    }
    private void ensureCapacity(){
        if(size == array.length){
            array = Arrays.copyOf(array, size*2);
        }
    }
}

四、栈的使用

这种如同堵在死胡同里,只能挨个蹦出来的结构到底有什么用嘞?

不知道大家接触过逆波兰表达式没有,这里科普一下哈。

逻辑提问式类似于算术表达式,对于检索而言,这种表达式并不是最优和最简洁的形式,需要进行必要的转换。1929年波兰的逻辑学家卢卡西维兹(Jan Lucasiewicz)提出了将运算符放在运算项后面的逻辑表达式,又称“逆波兰表达式”。采用这种表达式组织逻辑提问式非常方便检索运算,是日本的福岛先生最早将逆波兰表达式应用于情报检索的,故又称为“福岛方法”。 [2] 

逆波兰表达式又叫做后缀表达式,是一种没有括号,并严格遵循“从左到右”运算的后缀式表达方法,如下表所示:

逆波兰表达式

将正常表达式转化为逆波兰表达式,我们可以就可以利用栈的特性更容易的进行复杂表达式的运算,其运算逻辑如下:

基本逻辑如上,更复杂的工作量太大就不画了,如果对本列有兴趣的话可以移步牛客:逆波兰表达式求值

文章分享到此为止,如果感觉文章对您有用的话,可以顺手点个赞,或者收藏一下也行咧,感谢。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值