栈是一种“先入后出”的数据结构,只允许在一端增加和删除数据,其主要操作有push(入栈)、pop(出栈)和peek(查看)三种。在本文采用数组的方式来实现栈,结合下图进行讲解。
- push(入栈)
执行该操作时向栈中插入一个数据项。在插入的过程中,top先增加1(向上移动一个单元),再将数据项插入栈中。当栈满时,top等于数组容量的大小size-1,指向栈的最顶端。
- pop(出栈)
执行该操作时,移除栈顶箭头top所指着的数据项。移除过程中,首先移除由栈顶箭头top所指着的数据项,然后top减1(向下移动一个单元)。当把栈中最后一个数据项移除以后,top为-1,表示此时栈为空。
- peek(查看)
有时候只需要读取栈顶元素的值,而不需要移除它,peek操作查看的始终是栈最顶端的元素
以下使用java来实现栈,MyStack.java代码如下:
package achieve;
public class MyStack<T> {
private int maxSize; //the size of stack array
private Object[] stackArray; //stack array
private int top; //top of stack
public MyStack(int size){
maxSize = size;
stackArray = new Object[maxSize];
top = -1;
}
public void push(T t){
if (!isFull()){
stackArray[++top] = t; //top+1 then insert element
}else {
System.out.println("can't push : stack is full.");
}
}
public T pop(){
if (!isEmpty()){
return (T)stackArray[top--]; //remove element then top-1
}else {
System.out.println("can't pop : stack is empty");
}
return null;
}
public T peek(){
if (!isEmpty()){
return (T)stackArray[top];
}else {
System.out.println("stack is empty");
}
return null;
}
public boolean isEmpty(){
return (top == -1);
}
public boolean isFull(){
return (top == maxSize-1);
}
}
栈的效率
入栈和出栈的时间复杂度为O(1)。
栈实例1:单词逆序
用栈来实现单词逆序:首先,字母从输入的字符串中一个一个地取出来并压入栈中,接着将它们依次从栈中弹出,并显示出来。因为栈的“后进先出”的特征,所以字母的顺序就颠倒过来了。代码实现如下:
package demo;
import achieve.MyStack;
/**
* 栈实例1:单词逆序
*/
public class Reverse {
private String input;
private String ouput;
private MyStack<Character> stack;
public Reverse(String input){
this.input = input;
stack = new MyStack<Character>(input.length());
ouput = "";
}
public String doReserve(){
for (int i = 0;i < input.length();i++){
stack.push(input.charAt(i));
}
while (!stack.isEmpty()){
ouput += stack.pop();
}
return ouput;
}
}
栈实例2:分隔符匹配
这里我们以分隔符大括号“{ }”、中括号“[ ]”和小括号“( )”为例,每个左分隔符需要和右分隔符匹配。
以 a{b(c[d]e)f} 为例,随着字符串的读取,读到左分隔符,就压入栈中,非分隔符不必压入栈中;而每次读到一个右分隔符,就从栈顶弹出的左分隔符进行匹配。若匹配成功,则继续进行,否则程序停止,匹配结果为false,直到当字符串全部读取完成,且栈为空时,匹配结果才为true。
该过程随字符串的读取栈中的元素变化如下图所示:
实现该过程的java代码如下:
package demo;
import achieve.MyStack;
/**
* 栈实例2:分隔符匹配
*/
public class BracketCharacter {
private String input;
private MyStack<Character> stack;
public BracketCharacter(String str){
input = str;
stack = new MyStack<Character>(input.length());
}
public boolean check(){
int len = input.length();
for (int i = 0; i < len; i++){
char ch = input.charAt(i);
switch (ch){
case '{':
case '[':
case '(':
stack.push(ch); //若为左括号,则入栈
break;
case '}':
case ']':
case ')':
if (!stack.isEmpty()){ //检测到右括号,取栈中最后压入的元素进行校验
char begin = stack.pop();
if ((ch == '}' && begin != '{') ||
(ch == ']' && begin != '[') ||
(ch == ')' && begin != '(')){
return false; //不匹配,直接return
}
}else { //若栈为空,说明不可能匹配,直接return
return false;
}
break;
default:
break;
}
}
//for循环结束后若栈不为空,即栈中还有左括号为匹配
if (!stack.isEmpty())
return false;
return true;
}
}