栈
栈,相信大家都非常熟悉了,先进先出,后进后出,又叫做LIFO(先进先出)表,一般栈的模型是,存在某个元素位于栈顶,而该元素是唯一的可见元素
栈的实现方式
1、通过单链表,通过在表的顶端插入实现朴实,通过删除表顶端元素实现pop,top操作知识考察表顶端元素并返回他的值。
2、数组实现,就常规push,pop最后的元素,没什么特别的
Java中是怎么实现的栈
来看一下Stack在Java中的源码是怎么写的
首先,他是继承vector<>的,也就是说他是通过数组实现的栈
class Stack<E> extends Vector<E>
构造函数
public Stack() {
//只有一个空的构造函数
}
push方法
public E push(E item) {
//添加元素
addElement(item);
return item;
}
public synchronized void addElement(E obj) {
modCount++;
//确认是否需要扩容等操作
ensureCapacityHelper(elementCount + 1);
//将新元素放到当前数组最后元素位置的下一位
elementData[elementCount++] = obj;
}
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
//判断数组总的大小和当前数组内元素的个数的大小判断是否需要扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
pop和peek
public synchronized E pop() {
E obj;
int len = size();
//调用peek()方法,拿到当前栈顶,也就是数组尾的值
obj = peek();
//移除当前数组尾的元素
removeElementAt(len - 1);
return obj;
}
public synchronized E peek() {
int len = size();
if (len == 0)
//数组已空
throw new EmptyStackException();
//返回数组尾的值
return elementAt(len - 1);
}
public synchronized E elementAt(int index) {
//取数组对应位置的值
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
}
return elementData(index);
}
其他操作
//通过数组大小判断是否为空
public boolean empty() {
return size() == 0;
}
//查找元素
public synchronized int search(Object o) {
// 查找角标
int i = lastIndexOf(o);
if (i >= 0) {
return size() - i;
}
return -1;
}
public synchronized int lastIndexOf(Object o) {
//从数组的最后一位开始查找
return lastIndexOf(o, elementCount-1);
}
public synchronized int lastIndexOf(Object o, int index) {
//角标大于当前数组的大小
if (index >= elementCount)
throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
//通过循环来查找o的值,找到就返回对应角标
if (o == null) {
for (int i = index; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = index; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
栈的使用
讲到栈,想到了之前leetcode上的一道题,用栈操作十分简单,我们研究一下
Given a string containing just the characters '('
, ')'
, '{'
, '}'
, '['
and ']'
, determine if the input string is valid.
An input string is valid if:
- Open brackets must be closed by the same type of brackets.
- Open brackets must be closed in the correct order.
Note that an empty string is also considered valid.
简单的写一下,分析见代码
package listTest;
import java.util.Stack;
/**
* @Author fitz.bai
* @Date 2018/9/13 19:42
*/
public class MyStack {
public static void main(String[] args) {
String s = "{}([])";
/**流程
循环1:判断'{',栈中存入'}',栈顶为'}'
循环2:判断'}',栈中弹出'}',栈为空
循环3:判断'(',栈中存入')',栈顶为')'
循环4:判断'[',栈中存入']',栈顶为']'
循环5:判断']',栈中弹出']',栈顶为')'
循环6:判断')',栈中弹出')',栈为空
*/
System.out.println(resolution(s));
}
public static boolean resolution(String s) {
//建立一个栈
Stack<Character> stack = new Stack<>();
//针对传入的String,转换成字符数组,对每一个字符进行匹配辨识
for (char c : s.toCharArray()) {
//如果遇到的左半边,将右半边存入到栈中
if (c == '(') {
stack.push(')');
} else if (c == '{') {
stack.push('}');
} else if (c == '[') {
stack.push(']');
//关键步骤
//是否为空的判断,是针对第一个传入的就是右半边,直接false
//判断pop后是否等于当前的c,判断是否匹配
//比如当前c为')',则当前栈顶存入的必须是')',否则就不匹配,
//因为每当有一个右半部分出现,必定在其前面会有一个左半边对应,
//当当前出现时,可以认为其左边的所有成对儿的均已匹配,且被弹出,
//则剩下的必定为当前的匹配项,若不是则意味着不合法。
} else if (stack.isEmpty() || stack.pop() != c) {
return false;
}
}
return stack.isEmpty();
}
}
总结
Stack比较适合在平衡符号,以及后缀表达式等方面的使用。