一 API
栈是一种线性数据结构,遵从 LIFO(后进先出)的操作顺序,所有操作都是在顶部进行。
Java 集合框架中的 Stack 继承自 Vector:跟 Vector 一样,它是 数组实现的栈。jdk1.8源码如下:
public
class Stack<E> extends Vector<E> {
/**
* Creates an empty Stack.
*/
public Stack() {
}
/**
* Pushes an item onto the top of this stack. This has exactly
* the same effect as:
* <blockquote><pre>
* addElement(item)</pre></blockquote>
*
* @param item the item to be pushed onto this stack.
* @return the <code>item</code> argument.
* @see java.util.Vector#addElement
*/
public E push(E item) {
addElement(item);
return item;
}
/**
* Removes the object at the top of this stack and returns that
* object as the value of this function.
*
* @return The object at the top of this stack (the last item
* of the <tt>Vector</tt> object).
* @throws EmptyStackException if this stack is empty.
*/
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
/**
* Looks at the object at the top of this stack without removing it
* from the stack.
*
* @return the object at the top of this stack (the last item
* of the <tt>Vector</tt> object).
* @throws EmptyStackException if this stack is empty.
*/
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}
/**
* Tests if this stack is empty.
*
* @return <code>true</code> if and only if this stack contains
* no items; <code>false</code> otherwise.
*/
public boolean empty() {
return size() == 0;
}
/**
* Returns the 1-based position where an object is on this stack.
* If the object <tt>o</tt> occurs as an item in this stack, this
* method returns the distance from the top of the stack of the
* occurrence nearest the top of the stack; the topmost item on the
* stack is considered to be at distance <tt>1</tt>. The <tt>equals</tt>
* method is used to compare <tt>o</tt> to the
* items in this stack.
*
* @param o the desired object.
* @return the 1-based position from the top of the stack where
* the object is located; the return value <code>-1</code>
* indicates that the object is not on the stack.
*/
public synchronized int search(Object o) {
int i = lastIndexOf(o);
if (i >= 0) {
return size() - i;
}
return -1;
}
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = 1224463164541339165L;
}
可以看到pop跟peek返回值一样,只是多了一步移除栈顶元素操作。Vector 是线程安全的。
二 应用demo
场景1 简单括号匹配:
Given a string containing just the characters '('
, ')'
, '{'
, '}'
, '['
and ']'
, determine if the input string is valid.
The brackets must close in the correct order, "()"
and "()[]{}"
are all valid but "(]"
and "([)]"
are not.
package com.daojia.collect;
import java.util.Stack;
public class StackTest {
public boolean isValid(String input){
int stackSize = input.length();
Stack stack= new Stack();
int x=0;
for (char c : input.toCharArray()) {
switch (c) {
case '{':
case '[':
case '(':
stack.push(c);
break;
case '}':
case ']':
case ')':
if(!stack.isEmpty()) {
char chx = (char) stack.pop();
if ((c == '}' && chx != '{') ||
(c == ']' && chx != '[') ||
(c == ')' && chx != '(')
) {
System.err.println("Error:" + c + "at "+ x );
return false;
}
}else {
System.err.println("Error:" + c + "at "+ x );
return false;
}
break;
default:
break;
}
x++;
}
return stack.isEmpty();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String a = "(())abc{[(])}"; // 左右括号次序匹配不正确
String b = "(()))abc{[]}"; // 右括号多于左括号
String c = "(()()abc{[]}"; // 左括号多于右括号
String d = "(())abc{[]()}"; // 左右括号匹配正确
StackTest test = new StackTest();
System.out.println("a:"+test.isValid(a));
System.out.println("b:"+test.isValid(b));
System.out.println("c:"+test.isValid(c));
System.out.println("d:"+test.isValid(d));
}
}
场景2 生成n对匹配的括号:
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
For example, given n = 3, a solution set is:
"((()))", "(()())", "(())()", "()(())", "()()()"
这道题要生成正确形式的括号匹配的数量,其实就是卡特兰数,参见百科
单纯的搜索这个,常见的解法是基于递归实现的,但是把背后的原理说明白的不太多,多是c++的代码,基于vector。
题目转换为:有个队列,
假设在位置k我们还剩余left个左括号和right个右括号,如果left>0,则我们可以直接打印左括号,而不违背规则。
能否打印右括号,我们还必须验证left和right的值是否满足规则,如果left>=right,则我们不能打印右括号,因为打印会违背合法排列的规则,
否则可以打印右括号。如果left和right均为零,则说明我们已经完成一个合法排列,可以将其打印出来
package com.daojia.collect;
import java.util.Stack;
public class StackTest2 {
public static void generate(int leftNum,int rightNum,String s,Stack result){
//都为零,输出
if( leftNum ==0 && rightNum ==0){
result.push(s);
}
//剩余左括号数>0,可以输出左括号
if(leftNum >0){
generate(leftNum-1,rightNum,s+'(',result);
}
//剩余右括号数>0,且剩余左括号数<右括号数,可以输出右括号
if(rightNum>0 && leftNum<rightNum){
generate(leftNum,rightNum-1,s+')',result);
}
}
public static Stack generateParenthesis(int n){
Stack s =new Stack();
generate(n,n,"",s);
return s;
}
public static void main(String[] args) {
Stack s =generateParenthesis(3);
while(!s.isEmpty())
{
System.out.println(s.pop());
}
}
}
运行结果:
()()()
()(())
(())()
(()())
((()))
还有个典型的场景是后缀表达式的计算,单独整理一下。
参考:
https://blog.youkuaiyun.com/yutianzuijin/article/details/13161721