链表实现栈结构及应用场景描述

1.栈的特点

仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。如果用链表实现栈,怎么利用链表去做呢,我们可以把链表头看成栈顶,链尾堪称栈底,添加元素的时候,元素添加到链表头,删除的时候,删除链表头即可。

2.代码实现

2.1先构建一个链表实现,方便自定义链表的操作

代码如下,具体实现可参考上篇文章

public class StackBaseLink<E> {
    /**
     * 虚拟头节点,不存储实际元素
     */
    private Node head;
    private int size;

    public StackBaseLink() {
        head = new Node(null, null);
        size = 0;
    }

    /**
     * 内部类,用来封装链表中每个节点的属性
     */
    private class Node{
        /**
         * 链表中每个节点的值
         */
        private E e;
        /**
         * 指向链表中下个节点的指针
         */
        private Node next;

        private Node(E e, Node next) {
            this.e = e;
            this.next = next;
        }
    }

    public int size() {
        return size;
    }

    public void addFirst(E e) {
        head.next = new Node(e, head.next);
        size++;
    }

    public E removeFirst() {
        if (size == 0) {
            throw new IllegalArgumentException("队列为空");
        }
        Node temp = head.next;
        E result = null;
        if (temp != null) {
            result = temp.e;
        }
        head.next = head.next.next;
        size--;
        return result;
    }


    @Override
    public String toString() {
        StringBuilder sbr = new StringBuilder();
        Node temp = head.next;
        while (temp != null) {
            sbr.append(temp.e).append("->");
            temp = temp.next;
        }
        String s = sbr.toString();
        String result = s.substring(0, s.lastIndexOf("->"));
        return result;
    }
}

2.2构建自定义链表之后,开始构建自定义栈

public class LinkStack<E> {

    private StackBaseLink<E> baseLink;

    public LinkStack() {
        baseLink = new StackBaseLink<>();
    }

    public int size() {
        return baseLink.size();
    }

    public void add(E e) {
        baseLink.addFirst(e);
    }

    public E remove() {
        return baseLink.removeFirst();
    }
}

可以看到使用链表构建栈非常简单!好了,那栈到底有什么用呢,有哪些对应的场景?

3.栈的应用场景举例

3.1算术运算

什么意思呢,比如有一个算术表达式,2+3*4-1,这个算术在程序中怎么处理呢?

很简单,我们构建两个栈,其中一个保存操作数的栈,另一个是保存运算符的栈。我们从左向右遍历表达式,当遇到数字,我们就直接压入操作数栈;当遇到运算符,就与运算符栈的栈顶元素进行比较。
如果比运算符栈顶元素的优先级高,就将当前运算符压入栈;如果比运算符栈顶元素的优先级低或者相同,从运算符栈中取栈顶运算符,从操作数栈的栈顶取 2 个操作数,然后进行计算,再把计算完的结果压入操作数栈,继续比较。

示例如下:

如图,最后将14和1出栈相减即得到结果。

3.2括号匹配 

背景,假设表达式中只包含三种括号,圆括号 ()、方括号 [] 和花括号{},并且它们可以任意嵌套。比如,{[{}]}或 [{()}([])] 等都为合法格式,而{[}()] 或 [({)] 为不合法的格式。那我现在给你一个包含三种括号的表达式字符串,如何检查它是否合法呢?

这里也可以用栈来解决。我们用栈来保存未匹配的左括号,从左到右依次扫描字符串。当扫描到左括号时,则将其压入栈中;当扫描到右括号时,从栈顶取出一个左括号。如果能够匹配,比如“(”跟“)”匹配,“[”跟“]”匹配,“{”跟“}”匹配,则继续扫描剩下的字符串。如果扫描的过程中,遇到不能配对的右括号,或者栈中没有数据,则说明为非法格式。当所有的括号都扫描完成之后,如果栈为空,则说明字符串为合法格式;否则,说明有未匹配的左括号,为非法格式。这里就不用图说明了,文字已经描述很清楚了哈。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值