2.数组的动态扩容
以前基于数组实现的栈,是一个固定大小的栈,在初始化时就要指定栈的大小。当栈满之后,就无法再继续添加数据了。想要实现一个支持动态扩容的栈,我们只需要底层依赖一个支持动态扩容的数组就可以了。当栈满以后,我们就申请一个更大的数组,将原来的数据搬移到新数组中。代码如下:import java.util.Arrays; public class ArrayStack { private String[] items; //数组 private int maxSize; //存放的最大数量 private int currentSize; //当前元素的个数 //初始化数组 public ArrayStack(int maxSize){ this.items = new String[maxSize]; this.maxSize = maxSize; this.currentSize = 0; } //入栈 public boolean push(String item){ if(currentSize == maxSize) { //判断 int oldCurrent = maxSize; int newCurrent = oldCurrent << 1; //栈大小已经超过int的最大值 if (((newCurrent + 8) - Integer.MAX_VALUE) > 0) { return false; } //数组扩容 maxSize = newCurrent; items = Arrays.copyOf(items, newCurrent); } items[currentSize] = item; ++currentSize; return true; } //出栈 public String pop(){ if(currentSize == 0){ System.out.println("栈为空"); return null; }else{ String temp = items[currentSize-1]; --currentSize; return temp; } } public int getSize(){ return this.currentSize; } //测试 public static void main(String[] args) { ArrayStack arrayStack = new ArrayStack(4); arrayStack.push("1"); arrayStack.push("2"); arrayStack.push("3"); arrayStack.push("4"); arrayStack.push("5"); System.out.println(arrayStack.getSize()); System.out.println(arrayStack.pop()); System.out.println(arrayStack.getSize()); System.out.println(arrayStack.pop()); } }
3.链表的实现:
/** * 基于链表实现的栈 * @param <T> */ class LinkedStack<T> implements MyStack<T>{ private class ListNode{ T data; ListNode next; public ListNode(T data, ListNode next) { this.data = data; this.next = next; } } //栈顶元素 private ListNode top; //栈中元素个数 private static int currentSize; @Override public void push(T t) { ListNode newNode = new ListNode(t,null); if (top == null){ top = newNode; }else{ newNode.next = top; top = newNode; } currentSize++; } @Override public T pop() { if (currentSize == 0){ System.out.println("栈为空。"); return null; } T value = top.data; top = top.next; currentSize--; return value; } @Override public T peek() { if (currentSize == 0){ System.out.println("栈为空"); return null; } return top.data; } @Override public int size() { return currentSize; } @Override public boolean isEmpty() { return currentSize == 0; } }
栈在函数调用中的应用
操作系统给每个线程分配了一块独立的内存空间,这块内存被组织成“栈”这种结构,用来存储函数调用时的临时变量。每进入一个函数,就会将其中的临时作为栈帧入栈,当被调用函数执行完成,返回之后,将这个函数对应的栈帧出栈。
2.栈在表达式求值中的应用
利用两个栈,其中一个用来保存操作数,另一个用来保存运算符。我们从左向右遍历表达式,当遇到数字,我们就直接压入操作数栈;当遇到运算符,就与运算符栈的栈顶元素进行比较,若比运算符栈顶元素优先级高,就将当前运算符压入栈,若比运算符栈顶元素的优先级低或者相同,从运算符栈中取出栈顶运算符,从操作数栈顶取出2个操作数,然后进行计算,把计算完的结果压入操作数栈,继续比较。
3.栈在括号匹配中的应用
用栈保存为匹配的左括号,从左到右一次扫描字符串,当扫描到左括号时,则将其压入栈中;当扫描到右括号时,从栈顶取出一个左括号,如果能匹配上,则继续扫描剩下的字符串。如果扫描过程中,遇到不能配对的右括号,或者栈中没有数据,则说明为非法格式。 当所有的括号都扫描完成之后,如果栈为空,则说明字符串为合法格式;否则,说明未匹配的左括号为非法格式。(括号匹配的具体代码在上一篇博客中)。