栈的特点: 后进先出
package com.sxbdqn.stack;
/**
* 使用栈完成进制转换
* @author 北京乐学网老崔
*/
public class TestBaseConversion {
public static void main(String[] args) {
//
System.out.println( convert(100, 2));
System.out.println( convert(100, 8));
// System.out.println( convert(100, 16));
}
/**
* 把一个十进制整数 num转换为decimal指定的进制
* @param num 接收十进制整数
* @param decimal 指定进制
* @return 返回num这个整数对应 的decimal进制的字符串
*/
public static String convert(int num, int decimal) {
MyArrayStack stack = new MyArrayStack(); //保存余数
int remainder = num % decimal ; //余数
while( num != 0 ) {
stack.push( remainder ); //余数压栈
num = num / decimal;
remainder = num % decimal ;
}
//出栈,余数倒序
StringBuilder sb = new StringBuilder();
while( !stack.isEmpty() ) {
sb.append( stack.pop() );
}
return sb.toString();
}
}
检测表达式中括弧是否匹配
假设表达式中包含三种括弧: 小括弧(), 中括弧[], 大括弧{}, 这三种括弧可以任意嵌套;
(3+5) * [ 3-6] -{23/4}+([{}])
对于任意一个左括弧都需要有一个相应 的右括弧匹配, 最早出现的右括弧应该与最早出现的左括弧匹配. 符合栈的特点。
算法:
o 读取整个表达式, 如果是左括弧就直接入栈,等待与它对应的右括弧出现;
o 如果是右括弧, 则与当前栈顶的左括弧判断是否匹配
o 如果不匹配,说明表达式不合法
o 如果是右括弧, 栈已空, 表示不合法
o 读完整个表达式, 堆栈不空, 表示有左括弧没匹配上, 表达式不合法; 读完整个表达式,栈是空的表示所有括弧都能匹配。
package com.sxbdqn.stack;
/**
* 检测表达式中的括弧是否匹配
* @author 北京乐学网老崔
*/
public class TestBracketMatch {
public static void main(String[] args) {
//
System.out.println( bracketMatch("([{}])"));
System.out.println( bracketMatch("([{(}])"));
System.out.println( bracketMatch("([{}]))"));
}
//检测expression表达式 中的括弧是否匹配
public static boolean bracketMatch(String expression) {
MyArrayStack stack = new MyArrayStack() ; //保存左括弧
//遍历整个表达式, 如果是左括弧就入栈, 如果是右括弧,就出栈进行判断是否匹配
for( int i = 0 ; i < expression.length(); i++) {
//取出表达式的每个字符
char cc = expression.charAt(i);
switch (cc) {
case '(':
case '[':
case '{':
stack.push(cc); //左括弧入栈, Java可以自动装箱与拆箱
break;
case '}':
if ( !stack.isEmpty() && stack.pop().equals('{')) {
break;
}else {
return false;
}
case ']':
if ( !stack.isEmpty() && stack.pop().equals('[')) {
break;
}else {
return false;
}
case ')':
if ( !stack.isEmpty() && stack.pop().equals('(')) {
break;
}else {
return false;
}
}
}
//表达式遍历完后,如果栈是空的,表示括弧匹配,
if (stack.isEmpty()) {
return true;
}else {
return false;
}
}
}
算术表达式的求值
先乘除后加减
先括弧内再括弧外
从左到右进行运算
4 + 3 + ( 6 - 10 + 2*3) * 4
7 + ( 6 - 10 + 2*3) * 4
7 + ( -4 + 2*3) * 4
7 + ( -4 + 6) * 4
7 + 2 * 4
7 + 8
15
① 定义两个栈, 一个存储操作符operator, 一个存储操作数operand
② 读取表达式, 如果是操作数就存储到operand操作数栈
如果是操作符
o 操作符栈是空, 直接入栈
o 把操作符栈中的栈顶操作符与当前操作符进行优先级比较;
当前操作符优先级高, 操作符入栈;
当前操作符优先级低(栈顶操作符优先级高), 弹出栈顶操作符,从操作数栈中弹出两个操作数进行运算, 把运算结果存储到操作数栈中, 继续判断当前操作符与栈顶操作符的优先级。
③ 遍历完整个表达式, 两个栈都不为空, 依次弹出操作符opertor栈中的运算符与操作数栈中的两个操作数进行计算 , 把结果再存储到操作数栈中。
④ 如果操作符栈不为空, 或者操作数栈中的数不止有一个, 则表达式错误。
package com.sxbdqn.stack;
/**
* 使用栈计算算术表达式的值
* @author 北京乐学网老崔
*/
public class TestCalculateExpression {
public static void main(String[] args) {
//
String expression = "4+3+(6-10+2*3)*4";
double result = calculate( expression );
System.out.println( result );
}
//定义方法计算 指定表达式的值 : 6834+3+(6-10+2*3)*43
private static double calculate(String expression) {
MyArrayStack operatorStack = new MyArrayStack(); //存储操作符
MyArrayStack operandStack = new MyArrayStack(); //存储操作数
//遍历表达式中的操作数与操作符
for( int i = 0 ; i < expression.length() ; i++ ) {
char cc = expression.charAt(i);
//如果cc是数字
if ( Character.isDigit(cc)) {
//取出操作数
StringBuilder sb = new StringBuilder();
//只要是数字就是操作数的一部分
while( Character.isDigit(cc)) {
sb.append(cc); //6
i++; //取下个字符
if ( i >= expression.length() ) { //表达式结束
break;
}
cc = expression.charAt(i); //取下个字符
}
//操作数入栈
operandStack.push(sb.toString());
//修正i变量的值
i--;
// System.out.println( sb );
}else { //如果是操作符
//4+3+(6-10+2*3)*4
//1)栈为空, 直接把操作符入栈
if (operatorStack.isEmpty()) {
operatorStack.push(cc);
continue;
}
//2)操作符栈不为空的情况
while( !operatorStack.isEmpty()) {
char op1 = (char) operatorStack.peek();
//判断栈中运算符与当前运算符的优先级
if ( compareOperator(op1, cc) < 0 ) {
//当前运算符的优先级高于栈顶运算符的优先级
operatorStack.push(cc);
break;
}else if ( compareOperator(op1, cc) == 0) {
//当前运算符的优先级等于 栈顶运算符的优先级, 只有一种 情况, 左一半小括弧遇到右一半小括弧的情况
operatorStack.pop() ; //栈中左一半小括弧出栈
break;
}else { //栈顶运算符优先级高
//取出两个操作数
if (operandStack.isEmpty()) {
throw new RuntimeException("表达式错误");
}
double num1 = Double.parseDouble(operandStack.pop().toString());
if (operandStack.isEmpty()) {
throw new RuntimeException("表达式错误");
}
double num2 = Double.parseDouble(operandStack.pop().toString());
//取栈顶运算符
char operator = (char) operatorStack.pop();
//计算 num2 op num1
double result = compute(operator , num2, num1 );
//把结果存储到操作数栈中
operandStack.push(result);
//如果当前操作符栈为空, 新的操作符入栈
if ( operatorStack.isEmpty()) {
operatorStack.push(cc);
break;
}
}
}
}
}
//当表达式 遍历完后, 如果操作符栈不为空, 需要继续计算
while( !operatorStack.isEmpty()) {
char operator = (char) operatorStack.pop();
//如果操作数栈为空, 表达式错误
if (operandStack.isEmpty()) {
throw new RuntimeException("表达式错误");
}
double num1 = Double.parseDouble(operandStack.pop().toString());
if (operandStack.isEmpty()) {
throw new RuntimeException("表达式错误");
}
double num2 = Double.parseDouble(operandStack.pop().toString());
double result = compute(operator , num2, num1 );
operandStack.push(result);
}
//当操作符栈为空, 操作数栈中多于一个数, 表达式错误
if ( operandStack.getSize() > 1) {
throw new RuntimeException("表达式错误");
}
return Double.parseDouble(operandStack.pop().toString());
}
//计算 num1 op num2 表达式的值
private static double compute(char operator, double num1, double num2) {
switch (operator) {
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1 * num2;
case '/':
return num1 / num2;
}
return 0;
}
//判断两个运算符的优先级 ,如果op1优先级高返回正数, op2优先级高返回负数
private static int compareOperator(char op1, char op2) {
if ( op1 == '+' || op1 == '-') {
if (op2 == '*' || op2 =='/' || op2 =='(') {
//第一个运算符是 +-, 第二个运算符是 * / (
return -1;
}
}
if (op1 =='*' || op1 =='/') {
if ( op2 =='(') {
//第一个是*/, 第二个是(
return -1;
}
}
if ( op1 == '(') {
if (op2 == ')') {
return 0;
}else {
return -1;
}
}
return 1;
}
}