1345 - 算法3-4:表达式求值

算数四则运算的规则是1)先乘除,后加减;2)从左算到右;3)先括号内,后括号外。
由此,算式4+2*3-10/5的计算顺序为4+2*3-10/5=4+6-10/5=4+6-2=8。
给定一个以“#”作为结束符的算式,求出算式的结果。
给出严蔚敏《数据结构(C语言)》中的一段算法描述以作参考:

图1:表达式求值算法

<img width="524" height="361" alt="" src="http://tk.hustoj.com:80/upload/pimg1743_2.jpg" />

图2:表达式求值算法(续)

<img width="481" height="236" alt="" src="http://tk.hustoj.com:80/upload/pimg1743_3.jpg" />

<span style="font-size:10.5pt;">图</span><span style="font-size:10.5pt;">3</span><span style="font-size:10.5pt;">:表达式求值算法(续)</span>

题目输入

以“#”结尾的表达式,运算数为正整数。每个表达式占一行。

题目输出

输出表达式运算的结果。

输入/输出样例

题目输入

4+2*3-10/5#
3*(7-2)#
2*3/2#

题目输出

8
15
3

提示

提示:
使用栈来解决本题,很多人都会想到。但怎样建栈,却带来了问题。同样,严书上的代码实际上也给大家带来了问题。看过严书光盘中代码的人应该知道,代码中使用了两个栈,一个是存储运算符的,类型为char;另一个存储运算数,类型为float。而操作两个栈的函数都一样。要知道,除非像C++中使用泛型,C语言中却基本不能实现这样的操作。所以在C语言环境中需要将这两个栈结合在一起。由于char与int有种特别的联系,可以使用int来代替char存储运算符。
总结:
注意灵活运用栈,要是能够学习C++使用template就更好了。可以模拟STL了。

C语言解答

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned char prior[7][7]={
{'>','>','<','<','<','>','>'},
{'>','>','<','<','<','>','>'},
{'>','>','>','>','<','>','>'},
{'>','>','>','>','<','>','>'},
{'<','<','<','<','<','=',' '},
{'>','>','>','>',' ','>','>'},
{'<','<','<','<','<',' ','='}
};
char opset[7]={'+','-','*','/','(',')','#'};
int is_op(char c);
char precede(char a,char b);
int getIndex(char c);
int operate(int a,char op,int b);
int main()
{
  char expression[256];
  int evaluate=0;
  while(scanf("%s",expression)==1)
  {
      evaluate=evaluateExpression(expression);
      printf("%d\n",evaluate);
  }

  return 0;
}
int evaluateExpression(char *expression)
{
    char optr[256];
    int opnd[256];
    int top1,top2;
    char tempData[20];
    int data,a,b;
    char *c,dr[2];
    int x,i;
    char op;
    top1=top2=-1;
    optr[++top1]='#';
    c=expression;
    strcpy(tempData,"\0");
    while(*c!='#'||optr[top1]!='#')
    {
        if(!is_op(*c))
        {
            dr[0]=*c;
            dr[1]='\0';
            strcat(tempData,dr);
            c++;
            if(is_op(*c))
            {
                data=atoi(tempData);
                opnd[++top2]=data;
                strcpy(tempData,"\0");
            }
        }
        else
        {
            switch(precede(optr[top1],*c))
            {
                case '<':
                    optr[++top1]=*c;
                    c++;
                    break;
                case '=':
                    top1--;
                    c++;
                case '>':
                    op=optr[top1--];
                    b=opnd[top2--];
                    a=opnd[top2--];
                    opnd[++top2]=operate(a,op,b);
                    break;
            }
        }
    }
    return opnd[top2];
}

int is_op(char c)
{
    int i;
    for(i=0;i<7;i++)
      if(c==opset[i])
        return 1;
    return 0;
}

char precede(char a,char b)
{
    int i,j;
    i=getIndex(a);
    j=getIndex(b);
    return prior[i][j];
}

int getIndex(char c)
{
    int i;
    for(i=0;i<7;i++)
      if(c==opset[i])
        return i;
}

int operate(int a,char op,int b)
{
    int value;
    switch(op)
    {
        case '+':
             value=a+b;
             break;
        case '-':
             value=a-b;
             break;
        case '*':
            value=a*b;
            break;
        case '/':
            value=a/b;
            break;
    }
    return value;
}

C++解答

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define STACK_INIT_SIZE 100		// 存储空间初始分配量
#define STACKINCREMENT 10		// 存储空间分配增量
typedef int Status;
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW 0				// 栈分配溢出
#define OPSETSIZE 7
// 表3.1  算符间的优先关系
unsigned char Prior[7][7] = {
		{ '>', '>', '<', '<', '<', '>', '>' },
		{ '>', '>', '<', '<', '<', '>', '>' },
		{ '>', '>', '>', '>', '<', '>', '>' },
		{ '>', '>', '>', '>', '<', '>', '>' },
		{ '<', '<', '<', '<', '<', '=',	' ' },
		{ '>', '>', '>', '>', ' ', '>', '>' },
		{ '<', '<', '<', '<', '<', ' ', '=' } };

char OPSET[OPSETSIZE]= { '+', '-', '*', '/', '(', ')', '#' };

typedef int SElemType;

typedef struct {
	SElemType * base; // 在栈构造之前和销毁之后,base的值为NULL
	SElemType * top; // 栈顶指针
	int stacksize; // 当前已分配的存储空间,以元素为单位
} SqStack;

Status InitStack(SqStack &S) {
	// 构造一个空栈
	S.base = (SElemType *) malloc(STACK_INIT_SIZE * sizeof(SElemType));
	if (!S.base)
		exit(OVERFLOW); // 存储分配失败
	S.top = S.base;
	S.stacksize = STACK_INIT_SIZE;
	return OK;
}// InitStack

SElemType GetTop(SqStack S) {
	return *(S.top - 1);
}// GetTop

Status Push(SqStack &S, SElemType e) {
	// 插入元素 e 为新的栈顶元素
	if (S.top - S.base >= S.stacksize) { //栈满,追加存储空间
		S.base = (SElemType *) realloc(S.base, (S.stacksize + STACKINCREMENT)
				* sizeof(SElemType));
		if (!S.base)
			exit(OVERFLOW); // 存储分配失败
		S.top = S.base + S.stacksize;
		S.stacksize += STACKINCREMENT;
	}
	*S.top++ = e;
	return OK;
} // Push

Status Pop(SqStack &S, SElemType &e) {
	// 若栈不为空,则删除 S 的栈顶元素,用 e 返回其值,并返回 OK;否则返回 ERROR
	if (S.top == S.base)
		return ERROR;
	e = *--S.top;
	return OK;
} // Pop

Status StackEmpty(SqStack S) {
	// 若栈 S 为空栈,则返回 TRUE,否则返回 FALSE
	return S.top == S.base;
} // StackEmpty

void ClearStack(SqStack &S) {
	// 将栈 S 清空
	S.top = S.base;
} // ClearStack

void DestroyStack(SqStack &S) {
	// 销毁整个栈
	while (S.top != S.base) { // 释放栈中元素的空间
		free(--S.top);
	}
	S.top = S.base = NULL;
} // DestroyStack

int Operate(int a, unsigned char theta, int b) {
	switch (theta) {
	case '+':
		return a + b;
	case '-':
		return a - b;
	case '*':
		return a * b;
	case '/':
		return a / b;
	default:
		return 0;
	}
}

Status In(char Test, char* TestOp) {
	int Find = 0;
	int i;
	for (i = 0; i < OPSETSIZE; i++) {
		if (Test == TestOp[i])
			Find = 1;
	}
	return Find;
}

int ReturnOpOrd(char op, char* TestOp) {
	int i;
	for (i = 0; i < OPSETSIZE; i++) {
		if (op == TestOp[i])
			return i;
	}
	return 0;
}

char precede(char Aop, char Bop) {
	return Prior[ReturnOpOrd(Aop, OPSET)][ReturnOpOrd(Bop, OPSET)];
}

int EvaluateExpression(char* MyExpression) { // 算法3.4
	// 算术表达式求值的算符优先算法。
	// 设OPTR和OPND分别为运算符栈和运算数栈,OP为运算符集合。
	SqStack OPTR; // 运算符栈,字符元素
	SqStack OPND; // 运算数栈,实数元素
	char TempData[20];
	int Data, a, b;
	char *c, Dr[2];
	int x, theta;

	InitStack(OPTR);
	Push(OPTR, '#');
	InitStack(OPND);
	c = MyExpression;
	strcpy(TempData, "\0");
	while (*c != '#' || GetTop(OPTR) != '#') {
		if (!In(*c, OPSET)) { // 不是运算符则进栈
			Dr[0] = *c;
			Dr[1] = '\0';
			strcat(TempData, Dr);
			c++;
			if (In(*c, OPSET)) {
				Data = atoi(TempData);
				Push(OPND, Data);
				strcpy(TempData, "\0");
			}
		} else {
			switch (precede(GetTop(OPTR), *c)) {
			case '<': // 栈顶元素优先权低
				Push(OPTR, *c);
				c++;
				break;
			case '=': // 脱括号并接收下一字符
				Pop(OPTR, x);
				c++;
				break;
			case '>': // 退栈并将运算结果入栈
				Pop(OPTR, theta);
				Pop(OPND, b);
				Pop(OPND, a);
				Push(OPND, Operate(a, theta, b));
				break;
			} // switch
		}
	} // while
	return GetTop(OPND);
} // EvaluateExpression

int main(){

	char MyExpression[100];	// 获得表达式字符串
	while(gets(MyExpression) && strlen(MyExpression)){
		printf("%d\n", EvaluateExpression(MyExpression));
	}

	return 0;
}

提示

提示:
使用栈来解决本题,很多人都会想到。但怎样建栈,却带来了问题。同样,严书上的代码实际上也给大家带来了问题。看过严书光盘中代码的人应该知道,代码中使用了两个栈,一个是存储运算符的,类型为char;另一个存储运算数,类型为float。而操作两个栈的函数都一样。要知道,除非像C++中使用泛型,C语言中却基本不能实现这样的操作。所以在C语言环境中需要将这两个栈结合在一起。由于char与int有种特别的联系,可以使用int来代替char存储运算符。
总结:
注意灵活运用栈,要是能够学习C++使用template就更好了。可以模拟STL了。
时间限制 1 秒
内存限制 32 MB
讨论 统计
上一题 下一题