一.栈的概念
栈是一种先进后出的线性结构,你可以把它看做为一个弹匣,进栈就是把子弹压入弹匣,出栈就是射击一次,把子弹弹出弹匣,下面我们用java来实现一下栈的结构
二.栈Stack接口
我们定义Stack接口
/**
* 栈的方法定义
* @author JJH
* @param <E>
*/
public interface Stack<E> {
/**
* 栈顶入栈一个元素
* @param value
*/
boolean push(E value);
/**
* 从栈顶弹出一个元素,栈顶减一
* @return
*/
E pop();
/**
* 只获取栈顶元素的值
* @return
*/
E peek();
/**
* 判断栈是否为空
* @return
*/
boolean isEmpty();
/**
* 判断栈是否为满
* @return
*/
boolean isFull();
}
主要方法为入栈,出栈,获取栈顶元素值,判断栈为空,为满
三.单向带哨兵链表实现栈
/**
* 单向带哨兵链表实现栈
* @author JJH
*/
public class LinkedListStack<E> implements Stack<E>,Iterable<E>{
//节点类
static class Node<E>{
E value;
Node<E> next;
public Node(E value,Node<E> next){
this.value = value;
this.next = next;
}
}
/**
* 栈的总容量
*/
private int capacity;
/**
* 当前栈的元素个数
*/
private int size;
/**
* 头哨兵节点
*/
private Node<E> head;
/**
* 初始化
* @param capacity
*/
public LinkedListStack(int capacity){
this.capacity = capacity;
this.size = 0;
this.head = new Node<>(null,null);
}
@Override
public boolean push(E value) {
if(isFull()){
return false;
}
Node<E> node = new Node<>(value,head.next);
head.next = node;
size++;
return true;
}
@Override
public E pop() {
if(isEmpty()){
return null;
}
Node<E> first = head.next;
head.next = first.next;
size--;
return first.value;
}
@Override
public E peek() {
if(isEmpty()){
return null;
}
return head.next.value;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean isFull() {
return size == capacity;
}
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
Node<E> p = head.next;
@Override
public boolean hasNext() {
return p!=null;
}
@Override
public E next() {
E value = p.value;
p = p.next;
return value;
}
};
}
}
四.数组带top指针实现栈
* 数组实现栈
* 原理:
* 将数组的尾部作为栈顶,设置一个top栈顶指针
* 开始时指向索引0,也就是栈底位置,
* 当进栈时让top加一,出栈时top减一
* @author JJH
*/
public class ArrayStack<E> implements Stack<E>,Iterable<E>{
/**
* 数组
*/
private E[] array;
/**
* 栈顶指针
*/
private int top;
/**
* 栈容量
*/
private int capacity;
@SuppressWarnings("all")
public ArrayStack(int capacity){
this.capacity = capacity;
this.array = (E[]) new Object[this.capacity];
this.top = 0;
}
@Override
public boolean push(E value) {
if (isFull()) {
return false;
}
array[top++] = value;
return true;
}
@Override
public E pop() {
if (isEmpty()) {
return null;
}
return array[--top];
}
@Override
public E peek() {
if (isEmpty()) {
return null;
}
return array[top-1];
}
@Override
public boolean isEmpty() {
return top == 0;
}
@Override
public boolean isFull() {
return top == capacity;
}
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
int p = top;
@Override
public boolean hasNext() {
return p > 0;
}
@Override
public E next() {
return array[--p];
}
};
}
}
五.栈的一些习题
(1)有效括号
/**
* 有效括号
* 题目描述:
* 如果字符串为: "[],[()],{()},{[()]}" 这种类型,左右括号对称就是有效括号
* 如果是:"[[)[]}" 这种就不是有效括号
* 请判断是否是有效括号
*
* 思路:
* 遍历字符串,当遇到左括号 ( , [ , { 时,就把对应的右括号 ) , ] , } 压入栈中,
* 然后当碰到右括号时,就把该右括号和栈顶的右括号比较,如果相等,就把
* 栈顶的右括号弹出,相当于匹配成功一对括号,接着比较下一对,
* 如果不相等,就表示该字符串不是有效括号,直接返回false
*
* 如果最后栈为空,就表示全部匹配完成,该字符串是有效括号
*
*
*/
public class L20_usingKuohao {
private String str;
public L20_usingKuohao(String str){
this.str = str;
}
public boolean isUsing(){
LinkedListStack<Character> stack = new LinkedListStack<>(str.length());
for (int i = 0; i < str.length() ; i++) {
char c = str.charAt(i);
switch (c){
case '(':
stack.push(')');
break;
case '[':
stack.push(']');
break;
case '{':
stack.push('}');
break;
default:
if(stack.peek() == c){
stack.pop();
}else {
return false;
}
break;
}
}
return stack.isEmpty();
}
}
(2)求后缀表达式
/**
* 后缀表达式
*
* 例如: 1,2,*,3 转为 (1+2) * 3
*/
public class L120_lasetExpression {
public int getResult(String str){
LinkedList<String> stack = new LinkedList<>();
for (int i = 0; i <str.length() ; i++) {
char c = str.charAt(i);
switch (c){
case '+':
Integer b = Integer.parseInt(stack.pop());
Integer a = Integer.parseInt(stack.pop());
stack.add(String.valueOf(a+b));
break;
case '-':
Integer b1 = Integer.parseInt(stack.pop());
Integer a1 = Integer.parseInt(stack.pop());
stack.add(String.valueOf(a1-b1));
break;
case '*':
Integer b2 = Integer.parseInt(stack.pop());
Integer a2 = Integer.parseInt(stack.pop());
stack.add(String.valueOf(a2*b2));
break;
case '/':
Integer b3 = Integer.parseInt(stack.pop());
Integer a3 = Integer.parseInt(stack.pop());
stack.add(String.valueOf(a3/b3));
break;
default:
stack.add(String.valueOf(c));
break;
}
}
return Integer.parseInt(stack.pop());
}
(3)中缀表达式转后缀表达式
/**
* 中缀表达式转后缀表达式
*/
public class InFixToEndFix {
/**
* 思路:
* 1.当字符是非运算符时,直接拼接
* 2.当是运算符时:
* (1)若当前运算符优先级<=栈顶运算符优先级,就将栈中>=它的运算符全部弹出,它再入栈
* (2)若当前运算符优先级>栈顶运算符优先级,则将当前运算符压入栈中
* 3.循环弹出栈中剩余的运算符
*
* 带括号:
* 1.如果碰到 ( 就直接把它压入栈中
* 2.如果碰到 ) 就一直弹出栈顶,直到弹出 (
*/
public int proprity(char c){
switch (c){
case '*':
case '/':
return 2;
case '+':
case '-':
return 1;
case '(':
return 0;
default:
throw new IllegalArgumentException("运算符不合法"+c);
}
}
public String InfixToEndfix(String str){
LinkedList<Character> stack = new LinkedList<>();
StringBuilder sb = new StringBuilder(str.length());
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
switch (c){
case '+':
case '-':
case '*':
case '/':
if(stack.isEmpty()){
stack.add(c);
}else {
if(proprity(c)>proprity(stack.peek())){
stack.push(c);
}else {
while (!stack.isEmpty() && proprity(stack.peek())>=c){
sb.append(stack.pop());
}
stack.push(c);
}
}
break;
case '(':
stack.push(c);
break;
case ')':
while (!stack.isEmpty() && stack.peek()!='('){
sb.append(stack.pop());
}
stack.pop();
break;
default:
sb.append(c);
break;
}
}
while (!stack.isEmpty()){
sb.append(stack.pop());
}
return sb.toString();
}
读者可以在此基础上实现其他栈的实现,我们下期再见!