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括号匹配
背景,假设表达式中只包含三种括号,圆括号 ()、方括号 [] 和花括号{},并且它们可以任意嵌套。比如,{[{}]}或 [{()}([])] 等都为合法格式,而{[}()] 或 [({)] 为不合法的格式。那我现在给你一个包含三种括号的表达式字符串,如何检查它是否合法呢?
这里也可以用栈来解决。我们用栈来保存未匹配的左括号,从左到右依次扫描字符串。当扫描到左括号时,则将其压入栈中;当扫描到右括号时,从栈顶取出一个左括号。如果能够匹配,比如“(”跟“)”匹配,“[”跟“]”匹配,“{”跟“}”匹配,则继续扫描剩下的字符串。如果扫描的过程中,遇到不能配对的右括号,或者栈中没有数据,则说明为非法格式。当所有的括号都扫描完成之后,如果栈为空,则说明字符串为合法格式;否则,说明有未匹配的左括号,为非法格式。这里就不用图说明了,文字已经描述很清楚了哈。