栈是数据结构中非常重要的一个知识点,java底层虚拟机运行就是通过栈的形式,编译器会将代码打包编译成为一个一个的栈帧 然后逐个执行。
public class ArrayStack {
/**
* 最大容量
*/
private int maxSize;
/**
* 栈顶位置
*/
private int top = -1;
/**
* 存放数据的数组
*/
private int[] stack;
public ArrayStack(int maxSize) {
this.maxSize = maxSize;
// 初始化数组
this.stack = new int[maxSize];
}
/**
* 栈空
*/
public boolean isEmpty() {
return this.top == -1;
}
/**
* 栈满
*/
public boolean isFull() {
return this.top == this.maxSize - 1;
}
/**
* 放入数据 入栈
*/
public void push(int val){
if(isFull()){
throw new RuntimeException("栈满-maxSize:"+maxSize);
}
stack[++top] = val;
}
/**
* 弹出数据 出栈
*/
public int pop(){
if(isEmpty()){
throw new RuntimeException("栈空...");
}
return stack[top--];
}
/**
* 打印
*/
public void print(){
for(int i=top;i>=0;i--){
System.out.printf("\tstack[%d]=%d\n",i,stack[i]);
}
}
public static void main(String[] args) {
ArrayStack stack = new ArrayStack(5);
stack.push(1);
stack.push(2);
stack.print();
System.out.println("pop:"+stack.pop());
stack.print();
}
}
public class LinkedStack {
private LinkedStackNode top;
private int maxSize;
private int size;
public LinkedStack(int maxSize){
this.maxSize = maxSize;
}
/**
* 栈空
*/
public boolean isEmpty(){
return size == 0;
}
/**
* 栈满
*/
public boolean isFull(){
return size == maxSize;
}
/**
* 入栈
*/
public void push(int val){
if(isFull()){
throw new RuntimeException("栈满:"+maxSize);
}
LinkedStackNode newTop = new LinkedStackNode(val);
newTop.next = top;
top = newTop;
size ++;
}
/**
* 出栈
*/
public int pop(){
if(isEmpty()){
throw new RuntimeException("栈空...");
}
int val = top.val;
top = top.next;
size--;
return val;
}
/**
* 打印
*/
public void print(){
LinkedStackNode temp = top;
while(temp != null){
System.out.println(temp);
temp = temp.next;
}
}
static class LinkedStackNode{
private int val;
private LinkedStackNode next;
public LinkedStackNode(int val){
this.val = val;
}
@Override
public String toString() {
return "LinkedStackNode{" +
"val=" + val +
'}';
}
}
public static void main(String[] args) {
LinkedStack stack = new LinkedStack(5);
stack.push(1);
stack.push(2);
stack.print();
System.out.println("pop:"+stack.pop());
stack.print();
System.out.println("pop:"+stack.pop());
// System.out.println("pop:"+stack.pop());
stack.push(1);
stack.push(2);
stack.push(1);
stack.push(2);
stack.push(1);
stack.push(2);
}
}
后面的应用都使用这个栈
public class CalculatorStack<T> {
/**
* 最大容量
*/
private final int maxSize;
/**
* 栈顶位置
*/
private int top = -1;
/**
* 存放数据的数组
*/
private final Object[] stack;
public CalculatorStack(int maxSize) {
this.maxSize = maxSize;
// 初始化数组
this.stack = new Object[maxSize];
}
public boolean isEmpty() {
return this.top == -1;
}
public boolean isFull() {
return this.top == this.maxSize - 1;
}
public void push(T val) {
if (isFull()) {
throw new RuntimeException("栈满-maxSize:" + maxSize);
}
stack[++top] = val;
}
public T pop() {
if (isEmpty()) {
throw new RuntimeException("栈空...");
}
T val = (T) stack[top];
stack[top] = null;
top--;
return val;
}
public T peek() {
if (isEmpty()) {
throw new RuntimeException("栈空...");
}
return (T) stack[top];
}
public void print() {
for (int i = top; i >= 0; i--) {
System.out.printf("\tstack[%d]=%s\n", i, stack[i]);
}
}
public int size() {
return top + 1;
}
}
public class Calculator {
/**
* 数栈
*/
private CalculatorStack<Integer> numStack;
/**
* 操作符栈
*/
private CalculatorStack<Character> operStack;
public Calculator() {
numStack = new CalculatorStack(10);
operStack = new CalculatorStack(10);
}
/**
* 执行计算
*
* @param expression
* @return
*/
public int execute(String expression) {
int index = 0;
// 第一个值 第二个值
int num1, num2, oper;
String keepNum = "";
int len = expression.length();
while (index < len) {
char c = expression.charAt(index);
if (isOper(c)) {
// 如果有多位数的话 就先给多位数入栈 再进行下面的处理
if (!"".equals(keepNum)) {
numStack.push(Integer.parseInt(keepNum));
keepNum = "";
}
// 当前扫描到的是符号
if (c == '(') {
// 当扫描到的是( 直接入符号栈 因为仅仅只是(并不能进行计算
operStack.push(c);
} else if (c == ')') {
// 如果当前扫描到的是) 那么要循环处理符号栈和数字栈中的值,
// 循环结束条件 当数字栈只有一个数字 或者符号栈下一个值为(
while (!operStack.isEmpty()) {
// 要先判断符号栈是否满足继续往下的条件 否则可能出现栈空的情况
oper = operStack.pop();
if (oper == '(' || numStack.size() == 1) {
break;
}
num1 = numStack.pop();
num2 = numStack.pop();
int val = calculate(num1, num2, oper);
numStack.push(val);
}
} else {
// 当符号栈有值并且优先级不低于当前的符号
// 这里一定要注意不低于 如果只判断大于的话 会导致 6 -7 +1 计算结果为 -2的情况
while (!operStack.isEmpty() && priority(operStack.peek()) >= priority(c)) {
// 从数值栈取出2个值 再取出符号栈中的值进行计算
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
int val = calculate(num1, num2, oper);
numStack.push(val);
}
// 符号直接入栈
operStack.push(c);
}
} else {
// 数值可能是多位数 所以不能直接入栈
keepNum += c;
}
index++;
}
// 将最后的值推入栈中 因为最后结束的时候没有符号,所以keepNum中还有最后一次的值
if (!"".equals(keepNum)) {
numStack.push(Integer.parseInt(keepNum));
}
// 计算栈内的数据
// 每次计算的逻辑的都是从数栈中取出2个数 然后从操作栈中获取一个符号 然后将计算结果再压入数值栈
// 直到符号栈为空
while (!operStack.isEmpty()) {
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
int result = calculate(num1, num2, oper);
numStack.push(result);
}
return numStack.pop();
}
/**
* 判断当前的值是否为操作符
*
* @param val
* @return
*/
public boolean isOper(int val) {
return val == '*' || val == '/' || val == '+' || val == '-' || val == '(' || val == ')';
}
/**
* 判断优先级
*
* @param oper
* @return
*/
public int priority(int oper) {
if (oper == '(' || oper == ')') {
// 括号的优先级应该是最低的 括号不能被普通的运算消耗掉 只能通过特定的if去按组消除
return -999;
}
if (oper == '*' || oper == '/') {
return 1;
}
return 0;
}
/**
* 执行计算
*
* @param a
* @param b
* @param oper
* @return
*/
public int calculate(int a, int b, int oper) {
int result;
switch (oper) {
case '+': result = a + b; break;
case '-': result = b - a; break;
case '*': result = a * b; break;
case '/': result = b / a; break;
default:
throw new RuntimeException("不支持的操作符:" + Character.toChars(oper));
}
return result;
}
public static void main(String[] args) {
String expression = "2-5*2+8";// 0
expression = "1+2-3*(4-2-1)+8";// 8
expression = "(4-2-1)*3";// 3
expression = "3*(4-2-1)";// 3
expression = "1-2*3+4*((5/5+8-7*2)-3)";// -37
Calculator calculator = new Calculator();
System.out.println(expression + "=" + calculator.execute(expression));
}
}
public class PolandNotation {
private final CalculatorStack<Character> s1;
private final CalculatorStack<String> s2;
public PolandNotation() {
s1 = new CalculatorStack<>(100);
s2 = new CalculatorStack<>(100);
}
/**
* 执行转换
*/
public String execute(String expression) {
int index = 0;
// 第一个值 第二个值
String keepNum = "";
int len = expression.length();
while (index < len) {
char c = expression.charAt(index);
if (isOper(c)) {
if (!"".equals(keepNum)) {
// 操作数直接入s2
s2.push(keepNum);
keepNum = "";
}
// 如果当前操作符是( 直接压入s1
if ('(' == c) {
s1.push(c);
} else if (')' == c) {
// 如果当前符号是) 那么依次弹出s1中的符号直到 遇到(为之 , () 这组符号不入s2
Character pop = s1.pop();
while (pop != '(') {
s2.push(pop.toString());
pop = s1.pop();
}
} else {
while (true) {
if (s1.isEmpty() || '(' == s1.peek()) {
// 当s1为空或者s1的栈顶为( 的时候 直接将当前符号压入s1
s1.push(c);
break;
} else if (priority(c) > priority(s1.peek())) {
// 如果当前操作符的优先级高于栈顶的操作运算符 那么也压入s1
// 注意 这里不能加等于
s1.push(c);
break;
} else {
// 将s1的栈顶弹出到s2中 然后再重新执行本循环
s2.push(s1.pop().toString());
}
}
}
} else {
// 数值可能是多位数 所以不能直接入栈
keepNum += c;
}
index++;
}
// 将最后一个数压入数栈
if (!"".equals(keepNum)) {
s2.push(keepNum);
}
// 将最后的操作符号压入栈中
while (!s1.isEmpty()) {
s2.push(s1.pop().toString());
}
StringBuilder result = new StringBuilder();
while (!s2.isEmpty()) {
result.append(s2.pop()).append(" ");
}
// 结果还需要反转
return result.reverse().toString().trim();
}
/**
* 判断当前的值是否为操作符
*/
public boolean isOper(int val) {
return val == '*' || val == '/' || val == '+' || val == '-' || val == '(' || val == ')';
}
/**
* 判断优先级
*/
public int priority(int oper) {
if (oper == '(' || oper == ')') {
// 括号的优先级应该是最低的 括号不能被普通的运算消耗掉 只能通过特定的if去按组消除
return 999;
}
if (oper == '*' || oper == '/') {
return 1;
}
return 0;
}
public static void main(String[] args) {
String expression = "(1+2)*3";
expression = "1+((2+3)*4)-5";
PolandNotation polandNotation = new PolandNotation();
System.out.println(expression + " <==> " + polandNotation.execute(expression));
}
}
public class PolandNotationCalculator {
/**
* 数栈
*/
private CalculatorStack<String> numStack;
public PolandNotationCalculator() {
numStack = new CalculatorStack(10);
}
public int execute(String normalExpression){
// 先将正常的表达式转换成为逆波兰表达式
String polandNotationExpression = new PolandNotation().execute(normalExpression);
return executePolandNotation(polandNotationExpression);
}
/**
* 执行计算
*/
public int executePolandNotation(String polandNotationExpression) {
String[] ss = polandNotationExpression.split(" ");
String num1, num2;
for (int i = 0; i < ss.length; i++) {
String cur = ss[i];
if (isOper(cur)) {
// 弹出2个数 和当前符号进行计算
num1 = numStack.pop();
num2 = numStack.pop();
int result = calculate(num1, num2, cur);
// 将结果再放入到数栈中
numStack.push(result + "");
} else {
numStack.push(cur);
}
}
// 弹出最后的值
return Integer.parseInt(numStack.pop());
}
/**
* 判断当前的值是否为操作符
*/
public boolean isOper(String val) {
return !Character.isDigit(val.charAt(0));
}
/**
* 执行计算
*/
public int calculate(String num1, String num2, String oper) {
int a = Integer.parseInt(num1);
int b = Integer.parseInt(num2);
int result;
switch (oper) {
case "+": result = a + b; break;
case "-": result = b - a; break;
case "*": result = a * b; break;
case "/": result = b / a; break;
default:
throw new RuntimeException("不支持的操作符:" + oper);
}
return result;
}
public static void main(String[] args) {
String expression = "3 4 + 5 * 6 -";// (3 +4)*5 -6 = 29
PolandNotationCalculator calculator = new PolandNotationCalculator();
System.out.println(expression + "=" + calculator.executePolandNotation(expression));
expression = "(3+4)*5-6";
System.out.println(expression+"="+calculator.execute(expression));
}
}