中缀表达式求值

中缀表达式求值

基于栈的两种不同的方法求值
第一种:先将中缀表达式转化为后缀表达式(逆波兰表达式),再将后缀表达式求值
第二种:利用两个栈直接求值
  
以下分别介绍两种方法
第一种:
1、利用栈先将中缀表达式转换为后缀表达式
2、然后利用栈求后缀表达式的值
【对应步骤具体操作】
1、先将中缀表达式转换为后缀表达式(注意:中缀表达式中数字和运算符之间没有空格,转换为后缀表达式后数字和运算符、数字和数字、运算符与运算符中间有空格,方便运算)
(1)依次扫描中缀表达式
(2)遇到数字输出到后缀表达式
(3)遇到运算符,有以下几种情况
  a:栈空直接入栈
  b:遇到’(‘直接入栈
  c:遇到’)‘一直出栈并输出,直到’(‘出栈为止,但’('不作为输出(因为后缀表达式中没有括号)
  d:遇到运算符优先级高于栈顶运算符优先级,则入栈
  e:遇到运算符优先级低于或等于栈顶运算符优先级,则出栈,直到其优先级高于栈顶运算符优先级时停止(或栈为空),最后再将其入栈
2、计算后缀表达式
(1)依次扫描后缀表达式
(2)遇到数值入栈
(3)遇到符号将栈顶两个元素进行相应运算,将运算结果再入栈,重复(1)(2)操作,直到扫描结束

【代码实现】

#include 
#define MAXSIZE 100
//判断表达式的优先级
int symcmp(char a, char b)
{
	if (b == '(')
		return 1;
	else if ((b == '*' || b == '/') && (a == '+' || a == '-' || a == '('))
		return 1;
	else if ((b == '+' || b == '-') && (a == '('))
		return 1;
	else
		return 0;
}
//中缀表达式转换为后缀表达式
void exp_transplant(char *str1, char *str2)
{
	char stack[MAXSIZE];//栈
	int top = -1;//栈顶指针
	int j = 0;
	for (int i = 0; str1[i] != '\0'; i++)
	{
		if (str1[i] >= '0' && str1[i] <= '9') //数字直接输出
			str2[j++] = str1[i];
		else
		{
			if (i != 0 && str2[j - 1] != ' ') //之间加空格
				str2[j++] = ' ';
			if (str1[i] == ')') //一直出栈并输出,直到'('出栈,但'('不输出
			{
				while (stack[top] != '(')
				{
					str2[j++] = stack[top--];
					str2[j++] = ' ';
				}
				top--;
			}
			else if (!symcmp(stack[top], str1[i])) //运算符优先级低,则出栈
			{
				while (top > -1 && (!symcmp(stack[top], str1[i]))) //要么栈为空、要么优先级为高,则停止出栈
				{
					str2[j++] = stack[top--];
					str2[j++] = ' ';
				}
				stack[++top] = str1[i]; 
			}
			else
			{
				stack[++top] = str1[i];
			}
		}
	}
	if (str2[j - 1] != ' ')
		str2[j++] = ' ';
	while (top > -1) //将栈中剩余的运算符输出
	{
		str2[j++] = stack[top--];
		str2[j++] = ' ';
	}
	str2[j - 1] = '\0';//方便后面计算后缀表达式
}
//计算后缀表达式
int cal_s(char *str)
{
	int stack[MAXSIZE];
	int top = -1, tmp = 0, k = 10;
	for (int i = 0; str[i] != '\0'; i++)
	{
		if (str[i] >= '0' && str[i] <= '9') //计算数值
			tmp = tmp * 10 + str[i] - '0';
		else if (str[i] == ' ') //遇到' '就入栈(入的是上一个for循环的tmp值)
		{
			stack[++top] = tmp;
			tmp = 0; //设置为0,计算下一个数值
		}
		else //遇到运算符进入,拿栈顶两个元素进行相应运算
		{
			switch (str[i])
			{
			case '+':tmp = stack[top - 1] + stack[top]; break;
			case '-':tmp = stack[top - 1] - stack[top]; break;
			case '*':tmp = stack[top - 1] * stack[top]; break;
			case '/':tmp = stack[top - 1] / stack[top]; break;
			}
			top -= 2;
		}
	}
	stack[++top] = tmp; //后缀表达式中最后一个运算符后没有空格,所有整个表达式的最后结果就没有入栈
	return stack[0];
}
//计算中缀表达式
int calculate_expression(char *str)
{
	char s[100]; //存放后缀表达式
	exp_transplant(str, s); //将中缀表达式转换为后缀表达式
	int ret = cal_s(s); //计算后缀表达式
	return ret;
}
int main()
{
	char *str = "50+7*3*(2+1)-3";
	int ret = calculate_expression(str);
	printf("表达式的结果是:%d\n", ret);
	return 0;
}

第二种:
利用两个栈直接求结果,一个是运算值栈(数值入的栈),一个是运算符栈(运算符入的栈)
【对应步骤具体操作】
(1)依次扫描中缀表达式
(2)遇到运算值直接入栈
(3)遇到运算符,有以下几种情况
  a:栈空直接入栈
  b:遇到’(‘直接入栈
  c:遇到’)‘一直出栈并拿运算值栈中的栈顶两个元素做相应的运算,直到’('出栈为止。(栈顶两个元素运算时注意次序,栈顶第二个运算值在前,第一个在后,例如:a为栈顶元素,b为此栈顶元素,两值做减法运算,b-a)
  d:遇到运算符优先级高于栈顶运算符优先级,则入栈
  e:遇到运算符优先级低于或等于栈顶运算符优先级,则出栈,直到其优先级高于栈顶运算符优先级时停止(或栈为空),最后再将其入栈
  f:直到中缀表达式扫描结束
(4)中缀表达式扫描结束后,如果运算符栈中还有运算符,一直出栈并与运算值栈做相应操作(与步骤(3)中c的操作相同),直到栈空
(5)此时运算值栈中剩一个元素,即为最终结果

【代码实现】

#include 
#include 
#define MAXSIZE 100
//判断表达式的优先级
int symcmp(char a, char b)
{
	if (b == '(')
		return 1;
	else if ((b == '*' || b == '/') && (a == '+' || a == '-' || a == '('))
		return 1;
	else if ((b == '+' || b == '-') && (a == '('))
		return 1;
	else
		return 0;
}
//计算运算值栈顶两个元素(a栈顶第一个元素,b栈顶第二个元素)
int calculate(char c,int a,int b)
{
	int tmp = 0;
	switch (c)
	{
	    case '+':tmp = b + a; break;
	    case '-':tmp = b - a; break;
	    case '*':tmp = b * a; break;
	    case '/':tmp = b / a; break;
	}
	return tmp;
}

//计算中缀表达式
int calculate_expression(char *str)
{
	int num_stack[MAXSIZE]; //运算值栈
	int num_top = -1; //运算值栈指针
	char sym_stack[MAXSIZE]; //操作符栈
	int sym_top = -1; //操作符栈指针
	int i = 0;
	while (str[i] != '\0')
	{
		if (isdigit(str[i]))//判断是否是数字字符
		{
			//将数字字符转换为数值型并入栈
		    int  val = 0;
			while (isdigit(str[i]))
			{
				val = val * 10 + str[i] - '0';
				i++;
			}
			num_stack[++num_top] = val;
		}
		else //符号
		{
			if (str[i] == ')')
			{
				while (sym_stack[sym_top] != '(')
				{
					int ret = calculate(sym_stack[sym_top], num_stack[num_top], num_stack[num_top - 1]); //计算栈顶两个元素
					sym_top--;
					num_top -= 2;
					num_stack[++num_top] = ret;
				}
				sym_top--;
				i++;
			}
			else if (!symcmp(sym_stack[sym_top], str[i]))
			{
				while (sym_top > -1 && (!symcmp(sym_stack[sym_top], str[i])))
				{
					int ret = calculate(sym_stack[sym_top], num_stack[num_top], num_stack[num_top - 1]); //计算栈顶两个元素
					sym_top--;
					num_top -= 2;
					num_stack[++num_top] = ret;
				}
				sym_stack[++sym_top] = str[i];
				i++;
			}
			else
			{
				sym_stack[++sym_top] = str[i];
				i++;
			}
		}
	}
	while (sym_top > -1)
	{
		int ret = calculate(sym_stack[sym_top], num_stack[num_top], num_stack[num_top - 1]); //计算栈顶两个元素
		sym_top--;
		num_top -= 2;
		num_stack[++num_top] = ret;
	}
	return num_stack[0];
}
int main()
{
	char *str = "50+3*(2+1)-5*5*(5+5)";
	int ret = calculate_expression(str);
	printf("表达式的结果是:%d\n", ret);
	return 0;
}

OK!!!到此结束。如果有什么问题,希望友友们多多指教,共同进步!加油!加油!加油!

你可能感兴趣的:(算法与数据结构,1024程序员节,数据结构)