栈
栈的定义
栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
简而言之,这种数据结构类似于长条形的存储空间,并且一端封闭,它的特点是先入后出。
数据呈现方式如下图:
需要特别注意的是,栈是一种逻辑结构,并不是一种物理上存在的数据结构,如果你要实现一个栈来存储数据,你可以使用数组或链表来实现。
入栈
现在我们要在栈中添加一个数据100,将100这个数据压入栈(push)。
栈只有一个入口,添加数据只能从栈顶一侧放入,新放入的数据位置成为新的栈顶。
出栈
出栈就是取出元素,专业术语叫做弹出元素(pop),因为它具有取出数据并且删除两个效果。
这就没有了指定弹出哪一个数据的说法了,你只能说弹出一个数据,至于弹出哪一个?永远都是处在栈顶那一个。
弹出一个数据:
再弹出一个数据:
效率
无论是入栈还是出栈,都只是涉及到栈顶的那一个元素,不涉及其他元素的移动,所以栈的出栈入栈时间复杂度都是O(1)。
使用场景
栈在实战中使用场景应该很少,但肯定是有的,比如需要每次访问最新的数据时,就可以选择栈来存储数据。
栈在计算机中是不可获取的机制,在CPU内部就有栈使用这个数据结构来进行函数调用和返回、数字转字符、表达式求值、走迷宫等等,只要数据的保存具有先进后出的需求,都优先考虑使用栈。
代码实现
栈的核心是入栈与出栈的规则,所以为了规避掉数据类型、扩容等问题,我这里使用动态数组ArrayList来实现
/** * @Description 栈 * @Author zhaobaolin * @Date 2019/5/26 */ public class MyStack<T> { private ArrayList<T> arr = new ArrayList<>(); public void push(T data) { arr.add(data); } private boolean isEmpty() { return arr.isEmpty(); } public T pop() { if(isEmpty()){ return null; } int index = arr.size() - 1; T data = arr.get(index); arr.remove(index); return data; } public static void main(String[] args) { MyStack myStack = new MyStack(); myStack.push("hello"); myStack.push(666); myStack.push("world"); myStack.push(888); System.out.println(myStack.pop()); System.out.println(myStack.pop()); System.out.println(myStack.pop()); System.out.println(myStack.pop()); System.out.println(myStack.pop()); } }
最小栈
/** * @Description * @Author zhaobaolin * @Date 2019/5/26 * * * 设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。 * * push(int x) -- 将元素 x 推入栈中。 * pop() -- 删除栈顶的元素。 * top() -- 获取栈顶元素。 * getMin() -- 检索栈中的最小元素。 */ public class MinStack { private List arr; private int minIndex = -1; public MinStack() { arr = new ArrayList(); } public void push(int x) { if(arr.isEmpty()){ minIndex = 0; } arr.add(x); if(x < (int)arr.get(minIndex)){ minIndex = arr.size() - 1; } } public void pop() { if(!arr.isEmpty()){ int i = arr.size() - 1; arr.remove(i); if(i == this.minIndex){ this.minIndex = getArrayListMinIndex(); } } } public int top() { if(arr.isEmpty()){ return -1; } int i = arr.size() - 1; int data = (int) arr.get(i); if(i == this.minIndex){ this.minIndex = getArrayListMinIndex(); } return data; } private int getArrayListMinIndex() { if(arr.isEmpty()){ return -1; } Object obj = Collections.min(arr); return arr.indexOf(obj); } public int getMin() { return this.minIndex >= 0 ? (int) arr.get(this.minIndex) : -1; } public static void main(String[] args) { //测试用例 /* MinStack minStack = new MinStack(); minStack.push(1); minStack.push(2); System.out.println(minStack.top()); // --> 返回 2 System.out.println(minStack.getMin()); // --> 返回 1 minStack.pop(); System.out.println(minStack.getMin()); // --> 返回 1 System.out.println(minStack.top()); // --> 返回 1 */ /* MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); System.out.println(minStack.getMin()); // --> 返回 -3. minStack.pop(); System.out.println(minStack.top()); // --> 返回 0. System.out.println(minStack.getMin());// --> 返回 -2. */ } }
有效的括号
这也是一道痕经典的题
/** * @Description * @Author zhaobaolin * @Date 2019/5/26 * * 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 * * 有效字符串需满足: * 左括号必须用相同类型的右括号闭合。 * 左括号必须以正确的顺序闭合。 * 注意空字符串可被认为是有效字符串。 * * 例如: * 输入: "()" 输出: true * 输入: "()[]{}" 输出: true * 输入: "(]" 输出: false * 输入: "([)]" 输出: false * 输入: "{[]}" 输出: true * 输入: "(([]){})" 输出: true */ public class Bracket { private Map map; private Stack stack; public Bracket() { map = new HashMap(); map.put("(",")"); map.put("{","}"); map.put("[","]"); } public boolean isValid(String s) { this.stack = new Stack(); s = s.trim(); int len = s.length(); for(int i=0;i<len;i++){ String str = s.substring(i,i+1); if(this.stack.empty()){ stack.push(str); continue; } String peek = (String)stack.peek(); //如果栈顶的元素不是该符号的对应 则判断该符号是否是起始符号 if(str.equals(map.get(peek))){ stack.pop(); }else{ if(map.containsKey(str)){ stack.push(str); }else{ return false; } } } return this.stack.empty(); } public static void main(String[] args) { Bracket bracket = new Bracket(); System.out.println(bracket.isValid("()")); // true System.out.println(bracket.isValid("()[]{}")); // true System.out.println(bracket.isValid("(]")); // false System.out.println(bracket.isValid("([)]")); // false System.out.println(bracket.isValid("{[]}")); // true System.out.println(bracket.isValid("(([]){})")); // true } }