前言
对于一个表达式(例如:(5-2)*3)的问题,需要考虑到字符之间的优先级,对于上述问题的求解有很多种,例如,变更为后缀表达式:52-3×;前缀表达式等。
本文采用最为简单的求解方案
一、问题拆解
问题式样:2×(2+6/3)-2+1
从左向右将表达式字符一个个读入栈中,数字放入数字栈(Opnd),字符放入符号栈(Optr)
先在Optr中存入‘#’
再存入第一个字符‘2’,为数字,压入Opnd
下一个字符‘×’(‘*’)
压入入符号栈的原则是,待存入字符的优先级比栈顶高,进行压栈操作;如果待存入字符的优先级比栈顶低,将栈顶字符取出,再从数字栈中取头两个数字进行相应的运算,计算结果压入数字栈中,再将一开始带存入字符与字符栈栈顶的元素进行优先级的比较…
顶栏表示待压入字符,左栏表示栈顶字符
’>‘表示,待压入字符优先级小;’<‘表示待压入字符优先级大;’=‘表示两者优先级相等,都出栈;’?‘表示将栈顶元素出栈
字符‘*’的优先级比‘#‘高,压入Optr
下一个字符’(‘比’*‘的优先级高,压入Optr
'2’压入Opnd
下一个字符‘+’,优先级高,压入Optr
数字6,压入Opnd
‘/’,压入Optr
数字3,压入Opnd
字符‘)’,优先级低
将Opnd的头两个数字(3和6)取出,和Optr栈顶元素(’/‘)进行运算
6/3=2
将运算结果压入Opnd
再将‘)’,与‘+’进行比较,优先级低,重复
再将‘(’,与‘)’进行比较,优先级相等,‘)’出栈
‘-’的优先级比‘*’低,重复
再将‘-’与‘#’进行比较,优先级高,压入Optr
数字2压入Opnd
'+'优先级比‘-’低
‘+’优先级比‘#’高,压栈Optr
数字1,压栈Opnd
最后一个字符‘#’,优先级低
‘#’与‘#’优先级相等,出栈
无字符,结果从Opnd出栈,为5
二、使用步骤
1.引入库
代码如下(示例):
struct stack* Optr = NULL;
struct stack* Opnd = NULL;
Optr=creatStack();
push_stack_node(Optr, '#');
Opnd=creatStack();
char ch = 0;
ch = getchar();
stack_data_type theta = 0;
stack_data_type a = 0;
stack_data_type b = 0;
while (ch != '#' || get_top(Optr) != '#')
{
if (!In(ch))
{
push_stack_node(Opnd, ch);
ch = getchar();
}
else
switch (Precede(get_top(Optr), ch,Optr))
{
case '<':
push_stack_node(Optr, ch);
ch = getchar();
break;
case '>':
theta = get_top(Optr);
pop_stack_node(Optr);
a = (stack_data_type)get_top(Opnd);
pop_stack_node(Opnd);
b = (stack_data_type)get_top(Opnd);
pop_stack_node(Opnd);
push_stack_node(Opnd, (stack_data_type)Operate(a, theta, b));
break;
case '=':
pop_stack_node(Optr);
ch = getchar();
break;
}
}
stack_print(*Opnd);
2.部分函数
代码如下(示例):
int In(char ch)
{
char arr[] = { '#', '%', '*', '-', '+', '/' ,'(',')'};
int i = 0;
for (i = 0; i < sizeof(arr); i++)
{
if (arr[i] == ch)
return 1;
}
return 0;
}
char Precede(stack_data_type t1, stack_data_type t2, struct stack* Optr)
{
char f = 0;
switch (t2)
{
case '+':
if (t1 == '(' || t1 == '#')
f = '<';
else
f = '>';
break;
case '-':
if (t1 == '(' || t1 == '#')
f = '<';
else
f = '>';
break;
case '*':
if (t1 == '*' || t1 == '/' || t1 == ')')
f = '>';
else
f = '<';
break;
case '/':
if (t1 == '*' || t1 == '/' || t1 == ')')
f = '>';
else
f = '<';
break;
case '(':
if (t1 != ')')
f = '<';
else
pop_stack_node(Optr);
break;
case ')':
if (t1 != '('&&t1 != '#')
f = '>';
else if (t1 == '(')
f = '=';
else
pop_stack_node(Optr);
break;
case '#':
if (t1 != '('&&t1 != '#')
f = '>';
else if (t1 == '(')
pop_stack_node(Optr);
else
f = '#';
break;
default:
printf("请输入合法字符\n");
exit(-1);
break;
}
return f;
}
int Operate(stack_data_type a, stack_data_type theta, stack_data_type b)
{
switch (theta)
{
case '+':
return a-48 + b ;
case '-':
return b - a+48;
case '*':
return (a - 48)*(b - 48) + 48;
case '/':
return (b-48) / (a-48)+48;
}
}
总结
对于一个表达式求值,从左至右将字符取出,如果是数字,放入数字栈中,如果是符号,放入符号栈中;
放入符号栈中有一定的原则,优先级高的压栈,优先级低的,从符号栈中出栈一个符号,再从数字栈中出栈两个数字,进行相应的运算,再将结果压入数字栈中;
最终得到一个空的符号栈和一个只有一个数的数字栈,
将数字栈的最后一个数字出栈,即为所求结果。