自己先写了一个 局限:只能处理0-9的数,中间结果和最后结果也只能是0-9 将操作数栈和操作符栈中的数据设置成了相同的数据类型,导致中间计算的时候特别麻烦,也修改了好久代码,不过最后结果也出来了 实现:运算符有“+-*/^()” 具体思路: 遇到空格直接跳过,遍历下一个字符 遇到数字则进操作数栈 遇到运算符则先进行判断,再处理 根据各种优先级进行判断 括号的匹配性也包含其中 |
实验书: 基本要求:输入一个算术表达式的字符串,包含数字、+、-、*、/,以及小括号,字符串以等号结束,输出该表达式的值,结果保留两位小数。 算法思想 设两个栈,一个用于放数字,一个用于放运算符,对输入的表达式的每个字符做已下不同的处理: (1)如果是数字或小数点,则处理这个数字,再将这个数字进栈1 (2)如果是运算符,则比较这个运算符和栈2的栈顶元素的优先级。 如果相等或更低,则从栈1取出两个数字,从栈2取出一个运算符,进行运算,将运算结果再存入栈1.直到栈2的栈顶元素的优先级更低,将这个运算符存入栈2. (3)如果是“)”,则从栈1取出两个数字,从栈2取出一个运算符,进行运算,将运算结果存入栈1。直到栈2的栈顶元素为"("。将这个左括号出栈。 到最后,栈2为空,栈1中剩最后一个数,就是该表达式的值。 |
两个的区别: 实验书没有处理空格 最后以等号结束 但是数字是任意数字甚至是小数 |
思考: 自己的程序用了一堆i++,continue; 实验书的程序都没有用过continue,好好想想???? 现在好像有点想明白为什么当时自己写的那个括号匹配的算法那么多continue,而实验书上却没有,因为可以用 if else 这种写法。执行了if的话,就不会再执行else了。 |
/*老师从来不走回头路,一遍扫描过去之后,所有的结果就出来了
先写伪代码,再写程序,逻辑会清晰很多
如果思路不清楚,会越变越乱
*/
/*
遍历表达式时,如果是操作数的话,直接进栈
如果是操作符的话,
(1)如果操作符栈为空,直接进栈
(2)如果操作符栈不为空,则比较当前操作符和操作符栈的栈顶操作符,
如果当前操作符优先级 大于 操作符栈的栈顶操作符,则进栈;
如果当前操作符优先级 小于等于 操作符栈的栈顶操作符的话,则取两个操作数进行运算,结果存回到操作数栈
*/
/*
这个程序栈里面存的都是字符,计算之后是两个的差值,就不是一个字符了,
所以再进栈时要加'0',保证其还是一个数字字符
*/
#include<stdio.h>
#include<math.h>
#include<malloc.h>
typedef unsigned char boolean;
#define TRUE 1
#define FALSE 0
typedef char ElemType;
#define MaxSize 50
typedef struct{
ElemType data[MaxSize];
int top;
}STACK, OPERAND, OPERATOR;
const char *opeStr = "+-*/^()";
ElemType computeExpression(char *str);
boolean isOperand(char ch);
boolean isOperator(char ch);
int priorLevel(char ch);
ElemType compute(ElemType x1, ElemType x2, char ch);
boolean pushElem(STACK *stack, ElemType x);
boolean popElem(STACK *stack, ElemType *x);
void showData(STACK *stack);
void showData(STACK *stack){
int i;
for(i = 0; i < stack->top+1; i++){
printf("%c ", stack->data[i]);
}
printf("\n");
}
boolean popElem(STACK *stack, ElemType *x){
if(stack->top != -1){
*x = stack->data[stack->top];
stack->top--;
return TRUE;
}
return FALSE;
}
boolean pushElem(STACK *stack, ElemType x){
if(stack->top != MaxSize-1){ //栈不满
stack->top++;
//printf("stack->top=%d\n", stack->top) ;
stack->data[stack->top] = x;
showData(stack);
return TRUE;
}
return FALSE;
}
ElemType compute(ElemType x1, ElemType x2, char ch){
switch(ch){
case '+': return (x1-'0')+(x2-'0') +'0';
case '-': return (x1-'0')-(x2-'0') +'0';
case '*': return (x1-'0')*(x2-'0') +'0';
case '/': return (x1-'0')/(x2-'0') +'0';
case '^': return pow((x1-'0'),(x2-'0')) +'0';
}
}
int priorLevel(char ch){
switch(ch){
case ')':
case '+':
case '-': return 1;
case '*':
case '/': return 2;
case '^': return 3;
case '(': return 4;
}
}
boolean isOperator(char ch){
int i;
for(i = 0; opeStr[i]; i++){
if(ch == opeStr[i]){
return TRUE;
}
}
return FALSE;
}
boolean isOperand(char ch){
return (ch >= '0' && ch <= '9');
}
ElemType computeExpression(char *str){
OPERAND *stackOperand = NULL;
OPERATOR *stackOperator = NULL;
int i = 0;
ElemType x1, x2, ch;
//栈的初始化
stackOperand = (OPERAND *)malloc(sizeof(OPERAND));
stackOperand->top = -1;
//初始栈为空,top为-1,进栈时,top++,再进栈
stackOperator = (OPERATOR *)malloc(sizeof(OPERATOR));
stackOperator->top = -1;
//遍历表达式
while(str[i]){
printf("\n\n各个字符为:%c\n\n", str[i]);
printf("操作数栈中有:");
showData(stackOperand);
printf("操作符栈中有:");
showData(stackOperator);
printf("stackOperand->top=%d, 这一步的运算结果是:%d\n",stackOperand->top, stackOperand->data[stackOperand->top]);
printf("");
if(str[i] == ' '){
i++;
continue;
}
if(isOperand(str[i])){
//进操作数栈
pushElem(stackOperand, str[i]);
i++;
continue;
}
if(isOperator(str[i])){
if(priorLevel(str[i]) > priorLevel(stackOperator->data[stackOperator->top])
//|| stackOperator->top == -1 || stackOperator->top == '('){
|| stackOperator->top == -1 || stackOperator->data[stackOperator->top] == '('){
//进操作符栈
pushElem(stackOperator, str[i]);
i++;
}else{
popElem(stackOperand, &x1);
popElem(stackOperand, &x2);
popElem(stackOperator, &ch);
pushElem(stackOperand, compute(x2, x1, ch));
}
if(str[i] == ')'){
popElem(stackOperator, &ch);
i++;
}
continue;
}
}
/*
最后不用whil循环,因为经过分析,到了最后零结束标志的时候,其实只剩下最后一步的计算
课本:课本在最后加了一个等于号,使得最后一步计算也包括在了前面的代码中,这样简化了代码
while(stackOperator->top != -1){
popElem(stackOperand, &x1);
popElem(stackOperand, &x2);
popElem(stackOperator, &ch);
pushElem(stackOperand, compute(x2, x1, ch));
}
*/
popElem(stackOperand, &x1);
popElem(stackOperand, &x2);
popElem(stackOperator, &ch);
pushElem(stackOperand, compute(x2, x1, ch));
popElem(stackOperand, &x1);
return x1;
}
/*数据验证
1+2+4
1+2 + 4
2 *3 + 2
2 +3 * 1
)2+3
*2+3
(2+3)*6
(2+3)*6)
(2+3)*6+5*(4^2)^2
(2+3)*(6/5^2)
(2+3)*(6/5^2)
( 2 +3)*(6/5^2)
( 2 + 3 ) * ( 6/5 ^ 2 )
( 2 + 3 ) * ( 6/ 5 ^ 2 )
(2 +5 *4)^2) )
//(2+2)*1
//(2+3*1-4)
//2*(3*2-4+1)
2 * ( 3*2-4+ 1)
*/
void main(void){
char str[MaxSize];
printf("请输入一个字符串:");
gets(str);
printf("表达式为:%s\n", str);
printf("表达式的值为:%c\n", computeExpression(str));
}
#include<stdio.h>
#include<string.h>
//验证: 1+2*3=
int priority(char x){
switch(x){
case '+':
case '-':
case '=': return 1;
case '*':
case '/': return 2;
case '(': return 3;
}
}
double compute(double x, double y, char op){
switch(op){
case '+': return x+y;
case '-': return x-y;
case '*': return x*y;
case '/': return x/y;
}
}
int main(){
char s2[500], str[1001], op;
double s1[500];
int top1=-1, top2=-1;
double x, y;
gets(str);
double value;
int i;
for(i = 0; i < strlen(str); i++){
if(str[i] >= '0' && str[i] <= '9'){
value = 0;
while(str[i] >= '0' && str[i] <= '9'){
value = value*10 + str[i] - '0';
i++;
}
if(str[i] == '.'){
int r = 10;
i++;
while(str[i] >= '0' && str[i] <= '9'){
value += (double)(str[i] - '0')/r;
r*=10;
i++;
}
}
s1[++top1] = value;
}
if(str[i] == ')'){
while(s2[top2] != '('){
y = s1[top1--]; //注意,先取出来的是第二个操作数
x = s1[top1--];
op = s2[top2--];
s1[++top1] = compute(x, y, op);
}
top2--;
}else{
while(top2!=-1 && s2[top2]!='(' && priority(str[i]) <= priority(s2[top2])){
y = s1[top1--]; //注意,先取出来的是第二个操作数
x = s1[top1--];
op = s2[top2--];
s1[++top1] = compute(x, y, op);
}
s2[++top2] = str[i];
}
}
printf("%.2f\n", s1[top1]);
}