Problem B: 算法3-4:表达式求值

74 篇文章 14 订阅
35 篇文章 2 订阅

Problem Description

算数四则运算的规则是1)先乘除,后加减;2)从左算到右;3)先括号内,后括号外。

由此,算式4+2*3-10/5的计算顺序为4+2*3-10/5=4+6-10/5=4+6-2=8。

给定一个以“#”作为结束符的算式,求出算式的结果。

给出严蔚敏《数据结构(C语言)》中的一段算法描述以作参考:

图1:表达式求值算法

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

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

Input Description

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

Output Description

输出表达式运算的结果。

Sample Input

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

Sample Output

8
15
3

Hint

提示:

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

总结:

注意灵活运用栈,要是能够学习C++使用template就更好了。可以模拟STL了。

 

#include <iostream>
using namespace std;
#define MAXSIZE 100
 
 
//定义顺序栈
typedef int Status;
typedef int SElemType;
typedef struct
{
    SElemType *top;
    SElemType *base;
    int stacksize;
}SqStack;
 
unsigned char Prior[7][7] = {
    {'>', '>', '<', '<', '<', '>', '>'},
    {'>', '>', '<', '<', '<', '>', '>'},
    {'>', '>', '>', '>', '<', '>', '>'},
    {'>', '>', '>', '>', '<', '>', '>'},
    {'<', '<', '<', '<', '<', '=', ' '},
    {'>', '>', '>', '>', ' ', '>', '>'},
    {'<', '<', '<', '<', '<', ' ', '='},
}; 
 
char OPSET[7] = { '+', '-', '*', '/', '(', ')', '#' };
 
 
//栈的初始化
void InitStack(SqStack &S)
{
    //S.base = new SElemType[MAXSIZE];
    S.base = (SElemType*)malloc(100 * sizeof(SElemType));
    if (!S.base)
    {
        return;
    }
    S.top = S.base;
    S.stacksize = MAXSIZE;
}
//入栈
void Push(SqStack &S, SElemType c)
{
    if (S.top - S.base >= S.stacksize)//栈满了但运算还要继续,就重新开辟内存
    {
        S.base = (SElemType*)realloc(S.base, (S.stacksize + 10) * sizeof(SElemType));
        if (!S.base)//如果base为空分配内存失败
        {
            return;
        }
        S.stacksize += 10;
    }
    *(S.top)++ = c;
}
 
//获取栈顶元素
Status GetTop(SqStack &S)
{
    SElemType e;
    if (S.top == S.base)
    {
        return 0;
    }
    e = *(S.top-1);
    return e;
}
  
//判断是否为运算符
Status In(char c, char str[])
{
    int i = 0;
    while (c != str[i])
    {
        i++;
        if (i > 7)
        {
            break;
        }
    }
    if (i < 7)
    {
        return 1;
    }
    return 0;
}
 
 
//判断优先级
Status precede(int a, char b)
{
    int i = 0;
    int j = 0;
    while (OPSET[i] != a)
    {
        i++;
    }
    while (OPSET[j] != b)
    {
        j++;
    }
    return Prior[i][j];
}
 
void Pop(SqStack &S, int &e)
{
    if (S.base == S.top)
    {
        return;
    }
    e = *(--S.top);
}
 
 
 
Status Operate(int a, int b, int c)
{
    switch (b)
    {
    case '+':
        return a + c;
    case '-':
        return a - c;
    case '*':
        return a * c;
    case '/':
        return a / c;
    }
 
}
 
void strcat(char *str1, char *str2)//字符串连接函数,把字符串str2连接到str1后 
{
    int i = 0, j = 0;
    while (str1[i] != '\0')
    {
        i++;
    }
    while (str2[j] != '\0')
    {
        str1[i++] = str2[j++];
    }
    str1[i] = '\0';
}
 
Status atoi(char *c)//把字符串转为数字 
{
    int data = 0, d = 0;
    int i = 0;
    while (c[i] != '\0')
    {
        data = data * 10 + c[i] - '0';
        i++;
    }
    return data;
}
char EvaluateExpression(char *MyExpression)
{
    //算术表达式求值的算符优先算法
    SqStack OPTR;//运算符栈,字符元素
    SqStack OPND; //运算数栈,实数元素
     
    InitStack(OPTR);//初始化运算符栈
    Push(OPTR, '#');//将#压入运算符栈
    InitStack(OPND);
 
    char TempData[20];
    int Data, a, b;
    char *c, Dr[2];
    int x, theta;
 
    c = MyExpression;
 
    TempData[0] = '\0';
    while (*c != '#' || GetTop(OPTR) != '#')
    {
        if (!In(*c, OPSET))//判断是否为运算符,(不是运算符入栈)
        {
            Dr[0] = *c;
            Dr[1] = '\0';
            strcat(TempData, Dr);//把Dr所指向的字符串追加到TempData字符串结尾
            c++;//前移
            if (In(*c, OPSET))
            {
                Data = atoi(TempData);// 把字符串转换为int。
                Push(OPND, Data);//入栈
                TempData[0] = '\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;
            }
        }
    }
    return GetTop(OPND);
}
int main()
{
    char str[100];
    while (scanf("%s", str) != EOF)
    {
        printf("%d\n", EvaluateExpression(str));
    }
    return 0;
}

此处加另外一种算法

#define _CRT_SECURE_NO_WARNINGS 1
#include <stack>
#include <iostream>
#include <string.h>
using namespace std;
#define MAXSIZE 100

char Prior[7][7] = {
	//+,   -,	*,	  /,  (,	),	#
	{'>', '>', '<', '<', '<', '>', '>'},
	{'>', '>', '<', '<', '<', '>', '>'},
	{'>', '>', '>', '>', '<', '>', '>'},
	{'>', '>', '>', '>', '<', '>', '>'},
	{'<', '<', '<', '<', '<', '=', ' '},
    {'>', '>', '>', '>', ' ', '>', '>'},
	{'<', '<', '<', '<', '<', ' ', '='}
};

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

stack<int>Num;//运算数
stack<char>Symbol;//符号

char str[MAXSIZE];//

bool IsNum(char ch)
{
	if (ch >= '0' && ch <= '9')
	{
		return true;
	}
	return false;
}

int GetSymbolnum(char ch)
{
	for (int i = 0; i < 7; i++)
	{
		if (ch == OPSET[i])
		{
			return i;
		}
	}
}

int FindNum(int &i)
{
	int mun = 0;
	int n = 1;
	while (IsNum(str[i]))
	{
		mun = mun * n + (str[i] - '0');
		n = 10;
		i++;
	}
	return mun;
}

int Calculate(int b, char c, int a)
{
	if (c == '+')
	{
		return b + a;
	}
	else if (c == '-')
	{
		return b - a;
	}
	else if (c == '*')
	{
		return b * a;
	}
	else if (c == '/')
	{
		return b / a;
	}
}

void Operation()
{
	int length = strlen(str);
	if (str[length - 1] != '#')
	{
		cout << "输入表达式尾部没有#" << endl;
		return;
	}
	Symbol.push('#');
	int i = 0;
	while (!Symbol.empty())//当Symbol为空停止运算
	{
		if (IsNum(str[i]))
		{
			Num.push(FindNum(i));
		}
		else//就是操作符
		{
			int x = GetSymbolnum(Symbol.top());
			int y = GetSymbolnum(str[i]);
			switch (Prior[x][y])
			{
			case '<':
			{
				Symbol.push(str[i]);
				i++;
				break;
			}
			case '>':
			{
				int a = Num.top();
				Num.pop();
				int b = Num.top();
				Num.pop();
				char c = Symbol.top();
				Symbol.pop();
				int d = Calculate(b, c, a);
				Num.push(d);
				
				break;
			}
			case '=':
			{
				Symbol.pop();
				i++;
				break;
			}
			}
		}
	}
	cout << Num.top() << endl;
}



int main()
{
	while (scanf("%s", str) != EOF)
	{
		Operation();
	}
	return 0;
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小木苓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值