在这里开始讲述关于java的数据结构,争取每日一更,或者两日一更,将所有java的数据结构相关的结构类型,在这里讲解,好了,现在我们开始来讲第一个结构类型,栈,在这里,我要用栈来实现关于算式的计算,在这里使用了后缀表达式。(声明大部分知识来自《java数据结构和算法》,笔者在这里写下读后总结以及自己的补充。)
什么是后缀表达式?这个大家学过c语言的都应该知道了,我要用java来实现,同样的,思路分为两个步骤,1、将中缀表达式(也就是我们经常使用的计算形式 如 1+2*3)转换为后缀表达式,2、将后缀表达式计算出来。
首先是第一个,我们需要建一个栈,笔者在这里建了一个类,StackTest:
<span style="font-size:18px;">public class StackTest {
private int maxsize;
private char[] a;
private int top;
public StackTest(int s){
maxsize = s;
a = new char[maxsize];
top = -1;
}
public void Push(char m){
a[++top] = m;
}
public char Pop(){
return a[top--];
}
public char peek(){
return a[top];
}
public char peekN(int n){
return a[n];
}
public int size(){
return top+1;
}
public boolean isEmpty(){
return (top == -1);
}
public boolean isFull(){
return (top == maxsize - 1);
}
}</span>
这个栈很简单,就不再赘述了,接下来就是重点了,关于如何将中缀转换为后缀表达,请注意代码中笔者的注释,能有效理解这个逻辑变化:
public class TransClass {
private String input;
private String output="";
private StackTest stackTest;
public TransClass(String s){
input = s;
int max = input.length();
stackTest = new StackTest(max);
}
public String doTrans(){ // 进行转换的方法
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
switch (ch) {
case '+':
case '-':
gotOper(ch,1); //进行判断,若是操作符,则进行比较优先级,若是从栈中的操作符优先级比较 高,或者一样,则进行出栈
break;
case '*':
case '/':
gotOper(ch,2); //优先级比加减高
break;
case '(':
stackTest.Push(ch); //全部入栈
break;
case ')':
gotParen(ch); //出栈进行运算,直到出栈到左括号
break;
default:
output = output + ch; //将操作数放在一个字符串中
break;
}
}
while (!stackTest.isEmpty()) {
output = output + stackTest.Pop(); //打印字符串和栈中的操作符
}
return output;
}
private void gotParen(char ch) {
while (!stackTest.isEmpty()) {
char chx = stackTest.Pop();
if (chx == '(') {
break; //如果是遇到左括号,则停止出栈操作
}else {
output = output + chx; //如果不是左括号,则将操作符并在操作数后面
}
}// end while
}// end gotParen
private void gotOper(char onThis, int pece1) {
while (!stackTest.isEmpty()) {
char opTop = stackTest.Pop(); //取出栈顶元素
if (opTop == '(') {
stackTest.Push(opTop); //如果遇到左括号,则将元素重新入栈
break;
}
else {
int pece2;
if (opTop == '+' || opTop == '-') {
pece2 = 1; //如果栈顶元素是加减,则优先级为1
}
else {
pece2 = 2; //如果是其他操作符,则优先级为2
}
if (pece2 < pece1) {
stackTest.Push(opTop); //若是出栈的操作符比获取的操作符的优先级要小,则重新压入栈中
break;
}
else {
output = output + opTop; //否则就将出栈的操作符放在操作数后面,两个操作数的优先级一样也是如此,例如A+B-C=AB+C-
}
}//end else(it isn't a operator)
}//end while
stackTest.Push(onThis); //然后将获取的新的字符入栈
}
注释已经写得很清楚了,笔者再补充一下,主要注意两个点,1、操作符优先级的比较。2、左右括号的情况处理。就是这两个点了,然后关于后缀表达式的计算,逻辑是,1、对字符串依次获取,若是操作数则将操作数入栈,如果是操作符,则将栈中的两个元素出栈。2、然后进行相应的计算,在这里需注意,每次得出的结果应压入栈中,最后再将结果出栈。
public int result(String inputStr){
int resLength = inputStr.length();
ResultStack mResultStack = new ResultStack(20);
char ch1;
int num1,num2,resultStr;
for (int i = 0; i < inputStr.length(); i++) {
ch1 = inputStr.charAt(i);
if (ch1 >= '0' && ch1 <= '9') {
mResultStack.Push((int)(ch1-'0'));
}else {
num2 = mResultStack.Pop();
num1 = mResultStack.Pop();
switch (ch1) {
case '+':
resultStr = num2 + num1;
break;
case '-':
resultStr = num2 - num1;
break;
case '*':
resultStr = num2 * num1;
break;
case '/':
resultStr = num2 / num1;
break;
default:
resultStr = 0;
break;
}//end switch
mResultStack.Push(resultStr);
}
}//end for
resultStr = mResultStack.Pop();
return resultStr;
}
最后主函数再进行调用:
public class TestDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
String input,output;
while (true) {
System.out.print("Enter infix :");
System.out.flush();
input = getString();
if (input.equals("")) {
break;
}
TransClass transClass = new TransClass(input);
output = transClass.doTrans();
System.out.println("后缀表达式为: " + output + '\n');
int result = transClass.result(output);
System.out.print("求解结果为: " + result + '\n');
}// end while
}//end main
private static String getString() throws IOException {
String result = "";
InputStreamReader reader = new InputStreamReader(System.in);
BufferedReader bufReader = new BufferedReader(reader);
result = bufReader.readLine();
return result;
}
}
运行结果为:
好了,关于栈的知识已经讲完了。