字符串表达式的计算
字符串表达式的计算
步骤:
(1) 初始化两个栈:运算符栈S1和储存中间结果的栈S2;
(2) 从左至右扫描中缀表达式;
(3) 遇到操作数时,将其压入S2;
(4) 遇到运算符时,比较其与S1栈顶运算符的优先级:
(4-1) 如果S1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
(4-2) 比栈顶高,也将运算符压入S1 (注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
(4-3) 比栈顶低或相同,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;
(5) 遇到括号时:
(5-1) 如果是左括号“(”,则直接压入S1;
(5-2) 如果是右括号“)”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到左括号为止,此时将这一对括号丢弃;
(6) 重复步骤(2)至(5),直到表达式的最右边;
(7) 将S1中剩余的运算符依次弹出并压入S2;
(8) 依次弹出S2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)。
例:1+((2+3)×4)-5

java版 | 详见
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
sc.close();
System.out.println(getResult(getPost(s)));
}
/**
* 计算后缀表达式的值
* @param list 后缀表达式
* @return
*/
public static int getResult(List<Character> list) {
Stack<String> stack = new Stack<>();
for(int i = 0; i < list.size(); i++) {
char c = list.get(i);
if(c >= '0' && c <= '9') { //当遇到操作数直接压栈
stack.push(c + "");
}
else {//当遇到操作符的时候,从栈中弹出两个元素,然后根据运算符的不同做相应的运算,然后把运算结果压栈。
int b = Integer.parseInt(stack.pop());
int a = Integer.parseInt(stack.pop());
if(c == '+') stack.push(a + b + "");
else if(c == '-') stack.push(a - b + "");
else if(c == '*') stack.push(a * b + "");
else stack.push(a / b + "");
}
}
//最终栈中肯定只剩下一个元素,就是计算的结果。
return Integer.parseInt(stack.pop());
}
/**
* 把中缀表达式转为后缀表达式
* 前提条件:操作数的范围为0-9,操作符为+,-,*,/,以及()
* @param s 字符串表达式
* @return
*/
public static List<Character> getPost(String s) {
Stack<Character> stack = new Stack<>(); //保存操作符
LinkedList<Character> list = new LinkedList<>(); //保存最终的后缀表达式
for(int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if(c >= '0' && c <= '9') list.add(c); //操作数直接输出到后缀表达式中
else if(c == '+' || c == '-' || c == '*' || c == '/') {
//把比当前操作符c的优先级高或者等于c的优先级的操作符依次弹出栈并保存到后缀表达式中,直到遇到栈顶操作符的优先级比c低
while(!stack.isEmpty()) {
if(compare(stack.peek()) >= compare(c)) {
list.add(stack.pop());
}
else break;
}
stack.push(c);//当前操作符c入栈
}
else if(c == '(') stack.push(c); //左括号直接入栈
else {
//当遇到右括号的时候,把栈中的操作符依次弹出并追加到后缀表达式中,直到遇到左括号停止,并把左括号弹出。
while(stack.peek() != '(') {
list.add(stack.pop());
}
stack.pop();
}
}
//把栈中所有的操作符全部弹出追加到后缀表达式中
while(!stack.isEmpty())list.add(stack.pop());
return list;
}
/**
* 计算运算符的优先级
* @param c 运算符
* @return
*/
public static int compare(char c) {
if(c == '+' || c == '-') return 1;
else if(c == '*' || c == '/') return 2;
else return 0;
}
}
c++版
#define STACK_MAX 64
#define BOTTOM_NUMBER -1
typedef struct{
int TOP;
const int BOTTOM;
char STACK_M[STACK_MAX];
}STACK_BASE_TY;
我们采用数组STACK_M 作为栈的实体,BOTTOM作为栈底,
使用数组作为栈的实体,那么就可以规定栈底的索引值为“-1”。
栈从0~STACK_MAX-1正向增长。
当然我们还要编写栈的操作方法,为了方便管理我们编写一个结构体来管理函数。
typedef struct {
void (*Initial) ( STACK_BASE_TY *pStack);
int (*Push) ( STACK_BASE_TY *pStack, int data);
int (*Pop) ( STACK_BASE_TY *pStack, char *pdata);
char (*GetTopData) ( STACK_BASE_TY *pStack);
int (*GetTopLocate) ( STACK_BASE_TY *pStack);
}STACK_OPTION_TY;
我们规划一下每个函数的功能:
1.初始化栈,初始化栈的目的是建立一个空栈。即将TOP指针指向BOTTOM。pStack指向要初始化的栈的实体。
2.压栈,将一个数据的值压入栈顶。返回0,栈满,压入错误;返回1,压栈成功。
3.出栈,弹出栈顶的数据。*pdata接收出栈数据的值。返回0,栈空,出栈错误;返回1,出栈成功。
4.获取栈顶数据值,但是栈顶指针不发生变化。
5.获取栈顶的位置。
void initialStack( STACK_BASE_TY *pStack )
{
int i;
pStack->TOP = -1;
for( i =0; i< STACK_MAX; i++ ) pStack->STACK_M[i]=0;
}
int pushStack( STACK_BASE_TY *pStack, int data )
{
pStack->TOP++;
if( pStack->TOP>=STACK_MAX )
{
pStack->TOP--;
return 0;
}
else
{
pStack->STACK_M[ pStack->TOP] = data;
return 1;
}
}
int popStack( STACK_BASE_TY *pStack, char *pdata )
{
if(pStack->TOP<=pStack->BOTTOM)
{
return 0;
}
else
{
*pdata = pStack->STACK_M[pStack->TOP];
pStack->TOP--;
return 1;
}
}
int getStackTopLocate(STACK_BASE_TY *pStack)
{
return pStack->TOP;
}
char getTopData( STACK_BASE_TY *pStack )
{
return pStack->STACK_M[pStack->TOP];
}
定义两个栈,
STACK_BASE_TY statck_option={0,-1,{0,0}};
STACK_BASE_TY statck_result={0,-1,{0,0}};
STACK_BASE_TY* const pOptionStatck = &statck_option;
STACK_BASE_TY* const pResultStatck = &statck_result;
statck_option存放运算符号,statck_result存放最终结果。
STACK_OPTION_TY stackOption = {initialStack,pushStack,popStack,getTopData,getStackTopLocate} ;
定义一个函数结构体,并且初始化,使得我们可以方便的调用栈的操作方法。
const char str[] = "(1+2+3)*(4+5)"; 测试公式
int main( )
{
unsigned int i;
char temp;
char opCh_0,opCh_1;
int compPr;
stackOption.Initial(pOptionStatck);
stackOption.Initial(pResultStatck);
for( i=0; i<strlen(str); i++)
{
switch( str[i])
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
stackOption.Push(pResultStatck,str[i]);
break;
case '+':
case '-':
if( stackOption.GetTopLocate(pOptionStatck) ==-1 )
{
stackOption.Push(pOptionStatck,str[i]);
}
else
{
opCh_0 = stackOption.GetTopData(pOptionStatck);
if( opCh_0=='(')
{
stackOption.Push(pOptionStatck,str[i]);
}
else
{
while((stackOption.GetTopLocate(pOptionStatck) !=-1 )&&
(opCh_0!='('))
{
if(stackOption.Pop(pOptionStatck,&opCh_0 )!=0)
{
if(opCh_0!='(')
{
stackOption.Push(pResultStatck, opCh_0);
}
}
}
stackOption.Push(pOptionStatck,str[i] );
}
}
break;
case '*':
case '/':
if( stackOption.GetTopLocate(pOptionStatck) ==-1 )
{
stackOption.Push(pOptionStatck,str[i]);
}
else
{
opCh_0 = stackOption.GetTopData(pOptionStatck);
if(( opCh_0=='(')||(opCh_0=='+')||(opCh_0=='-'))
{
stackOption.Push(pOptionStatck,str[i]);
}
else
{
while((stackOption.GetTopLocate(pOptionStatck) !=-1 )&&
(opCh_0!='('))
{
opCh_0 = stackOption.GetTopData(pOptionStatck);
if(( opCh_0=='(')||(opCh_0=='+')||(opCh_0=='-'))
{
break;
}
else
{
stackOption.Pop(pOptionStatck,&opCh_0);
stackOption.Push(pResultStatck,opCh_0);
}
}
stackOption.Push(pOptionStatck,str[i] );
}
}
break;
case '(':
stackOption.Push(pOptionStatck,str[i]);
break;
case ')':
if( stackOption.GetTopLocate(pOptionStatck) ==-1 )
{
}
else
{
opCh_0 = stackOption.GetTopData(pOptionStatck);
if( opCh_0=='(')
{
stackOption.Pop(pOptionStatck,&opCh_0);
}
else
{
while((stackOption.GetTopLocate(pOptionStatck) !=-1 )&&
(opCh_0!='('))
{
opCh_0 = stackOption.GetTopData(pOptionStatck);
if( opCh_0!='(')
{
stackOption.Pop(pOptionStatck,&opCh_0);
stackOption.Push(pResultStatck,opCh_0);
}
else
{
stackOption.Pop(pOptionStatck,&opCh_0);
}
}
}
}
break;
default:
break;
}
}
while(stackOption.Pop(pOptionStatck,&opCh_0)!=0)
{
stackOption.Push(pResultStatck,opCh_0);
}
while(stackOption.Pop(pResultStatck,&opCh_0)!=0)
{
printf("%c,",opCh_0);
}
printf("\n");
return 0;
}
浙公网安备 33010602011771号