中缀表达式:也就是一般的算术表达式,如"9+(3-1)*3+10/2这样的
后缀表达式:就是将运算符挪到操作数后面,但这样的挪动是有规则的,例如上式转换后缀表达式后是这样的:"9 3 1-4*+10 2/+"
中缀转后缀表达式规则:
从左到右遍历中缀表达式中的每一个·数字和符号:
1.如果是操作数就输出,成为后缀表达式的一部分
2.如果是运算符,先判定它与栈顶元素的优先级,如果栈顶元素优先级低比它低或相等,则入栈;
如果优先级高于它,则出栈当前栈顶元素到后缀表达式中,直到栈顶元素优先级比它高(即便两者优先级相等,也出栈)
然后在将此运算符进栈(如果出栈过程中遇到‘(’,停止出栈,将 此运算符进栈);
3.如果是‘(',直接进栈;
4.如果是‘)',将栈中元素出栈,放入后缀表达式中,直到遇到‘('为止,并且‘('也要被出栈,但不可以放入后缀表达式中,直接丢弃;
代码实现:
俺是先用一个字符串数组接收输入的中缀表达式,但是不能直接对这个字符数组直接转后缀 表达式,如果直接转,会发生多个操作数连在一起
无法区分的情况,例如这样"931-4*+10 2/+",9,3,1三个不同操作数连在一起成了一个操作数了, 为了避免这种状况,俺使用了一个指针数组,
将每个操作数从字符串数组中分离出来,并放在指针数组所指向的动态内存中,以此来将每个操作数区分开来,在将经过转换的表达式转换成
后缀表达式。
将字符串数组中的中缀表达式进行转换,防止操作数连在一起:
void checkInputConvert(char * infix, char ** opNum)
{
int index1 = 0;
int length = strlen(infix);
for (int i = 0; i < length;)
{
char ch = infix[i];
int index2 = 0;
int charNum = 0;
if (isNumber(ch))//判断是否是数字
{
charNum++;
opNum[index1] = (char*)calloc(charNum + 1,sizeof(char));
opNum[index1][index2++] = ch;
while (isNumber(infix[i + charNum]))
{
charNum++;//统计单个操作数所包含的字符个数
opNum[index1] = (char*)realloc(opNum[index1], sizeof(char)*(charNum + 1));
opNum[index1][index2++] = infix[i + charNum - 1];
}
i += charNum;
opNum[index1++][index2] = '\0';//设置字符串结束符
continue;//单个操作数已找完,跳出此次循环
}
if (isOperator(ch))//判断是否是操作符
{
opNum[index1] = (char*)calloc(2, sizeof(char));
opNum[index1++][index2] = ch;
i++;
continue;
}
if (ch == '(' || ch == ')')
{
opNum[index1] = (char*)calloc(2, sizeof(char));
opNum[index1++][index2] = ch;
i++;
continue;
}
printf("输入的数据有误,请重新输入!\n");
exit(1);
}
这其中还要用到其他判断函数,如下:
int isOperator(char ch)//判断是否是运算符
{
char op[5] = "+-*/";
for (int i = 0; i < 5; i++)
{
if (ch == op[i])
return 1;
}
return 0;
}
int isNumber(char ch)
{
if ((ch - '0') >= 0 && (ch - '0') <= 9)
return 1;
else
return 0;
}
//比较优先级,ch未中缀表达式中的运算符,op为栈中的运算符或‘(’
//当op1的优先级小于op2的优先级时返回-1,大于时返回1,等于时返回0
int comparePrior(char op1, char op2)
{
if (op1 == '+' || op1 == '-')
{
if (op2 == '*' || op2 == '/')
return -1;
if (op2 == '+' || op2 == '-')
return 0;
}
if (op1 == '*' || op1 == '/')
{
if (op2 == '*' || op2 == '/')
return 0;
if (op2 == '+' || op2 == '-')
return 1;
}
if (op2 == '(')
return 1;
}
再将将转换后的中缀表达式,转换为后缀表达式:
void infixToPrefix(char ** infix,char** prefix )//中缀表达式转后缀
{
stack<char> LS;
int index1 = 0;//指向infix中的下标
int index2 = 0;//指向prefix中的下标
while (infix[index1] != NULL)
{
char ch = infix[index1][0];
if (ch == '(')//左括号入栈
{
LS.push(ch);
index1++;//指向下一个字符串
continue;
}
if (isNumber(ch))//数字输出到temp中
{
int length = strlen(infix[index1]);
prefix[index2] = (char*)calloc(length + 1, sizeof(char));//测定该操作数所包含字符个数,并分配空间
prefix[index2][length] = '\0';
strcpy(prefix[index2++], infix[index1++]);//将字符串拷贝过来
continue;
}
if (isOperator(ch))//判断是不是操作符
{
if (LS.empty())//栈空不比较,直接入栈
{
LS.push(ch);
index1++;
}
else
{
if (comparePrior(ch, LS.top()) >= 0)//优先级高直接入栈
{
LS.push(ch);
}
else//优先级低需要将栈中优先级比ch高或等于的全部出栈
{//如果有多个操作符出栈,将会把这些操作符存在同同一指针指向的字符数组中
int num = 0;//记录要出栈的操作符的个数
char temp[100] = { 0 };//用来暂存出栈的存操作符
temp[num++] = LS.top();
LS.pop();
while (!LS.empty() && comparePrior(ch, LS.top()) <= 0)
{
temp[num++] = LS.top();
LS.pop();
}
LS.push(ch);//所有比ch优先级大于等于的操作符已经出栈完成,将ch入栈
prefix[index2] = (char *)calloc(++num, sizeof(char));
prefix[index2][--num] = '\0';
strcpy(prefix[index2++], temp);
}
index1++;
}
continue;
}
if (ch == ')')
{
int num = 0;//记录要出栈的操作符的个数
char temp[100] = { 0 };//用来暂存出栈的存操作符
while (LS.top() != '(')
{
temp[num++] = LS.top();
LS.pop();
}
LS.pop();//将‘(’出栈
prefix[index2] = (char *)calloc(++num, sizeof(char));
prefix[index2][--num] = '\0';
strcpy(prefix[index2++], temp);
index1++;
continue;
}
}
if (!LS.empty())
{
int num = 0;//记录要出栈的操作符的个数
char temp[100] = { 0 };//用来暂存出栈的存操作符
while (!LS.empty())//此时中缀表达式已扫完,若栈中有剩余操作符,全部弹出,追加到prefix中
{
temp[num++] = LS.top();
LS.pop();
}
prefix[index2] = (char *)calloc(++num, sizeof(char));
strcpy(prefix[index2], temp);
}
}
此时中缀表达式已转换未后缀表达式,计算后缀表达式的值:
算法过程自己百度......
int calcPrefix(char ** prefix)//计算后缀表达式求值
{
stack<double> LS;
int index1 = 0;
while (prefix[index1] != NULL)
{
int index2 = 0;
char ch;
if (isNumber(ch = prefix[index1][index2]))
{
double opNum = ch - '0';
while ((ch = prefix[index1][++index2]) != '\0')
opNum = opNum * 10 + (ch - '0');
LS.push(opNum);
index1++;
continue;
}
flag:
if (isOperator(ch = prefix[index1][index2]))
{
switch (ch)
{
case '+':
{
double opNum1 = LS.top();
LS.pop();
double opNum2 = LS.top();
LS.pop();
LS.push(opNum1 + opNum2);
while ((ch = prefix[index1][++index2]) != '\0')
goto flag;
index1++;
break;
}
case '-':
{
double opNum1 = LS.top();
LS.pop();
double opNum2 = LS.top();
LS.pop();
LS.push(opNum2 - opNum1);
while ((ch = prefix[index1][++index2]) != '\0')
goto flag;
index1++;
break;
}
case '*':
{
double opNum1 = LS.top();
LS.pop();
double opNum2 = LS.top();
LS.pop();
LS.push(opNum2 * opNum1);
while ((ch = prefix[index1][++index2]) != '\0')
goto flag;
index1++;
break;
}
case '/':
{
double opNum1 = LS.top();
LS.pop();
double opNum2 = LS.top();
LS.pop();
LS.push(opNum2 / opNum1);
while ((ch = prefix[index1][++index2]) != '\0')
goto flag;
index1++;
break;
}
}
continue;
}
}
return (LS.top());
}
最后就是主函数了:
#define _CRT_SECURE_NO_WARNINGS
#include<stack>
#include<string.h>
#include<stdio.h>
using namespace::std;
int isOperator(char ch);//判断是否是运算符
int comparePrior(char op1,char op2);//比较优先级
int isNumber(char ch);
void infixToPrefix(char ** infix, char ** prefix);//中缀表达式转后缀
int calcPrefix(char ** prefix);//计算后缀表达式求值
void checkInputConvert(char * ch,char ** infix);//将输入的字符串转换为合理的中缀表达式
int main()
{
while (1)
{
char ch[100] = "12+33-5*65/10+((343+34)*2)*3/4+34";
char * infix[100] = { 0 };
char * prefix[100] = { 0 };
//printf("请输入要计算的表达式:\n");
//scanf("%s", ch);
printf("输入的中缀表达式为:%s\n", ch);
checkInputConvert(ch, infix);
char** p = infix;
while (*p != NULL)
{
printf("%s", *p);
p++;
}
infixToPrefix(infix, prefix);
printf("\n%d\n",calcPrefix(prefix));
system("pause");
}
return 0;
}
写的不好。。。。。