刚开始1.5倍速没看懂小甲鱼说的逆波兰,然后1倍速慢慢听 懂了 emmm 我可能是个小智障 先mark一下 ,睡醒再来写👧
- 中缀表达式转后缀表达式
- 逆波兰的原理
- 上述的实现
首先中缀表达式转后缀表达式的原理:
①优先级的判定
②操作符入栈时,若此时栈顶元素的优先级高于将要入栈的元素X,此时需要将栈内优先级大于等于X优先级的操作符都pop弹出,放在数字的后面
③一对小括号 当操作符遇到“)”时,依次弹出元素,直至遇到匹配的“(”为止
以上就是中缀转后缀的核心思想。
其次逆波兰的核心思想:
检测输入的是数还是字符,将数字压栈,直到遇到操作符,弹出栈顶的两个元素进行计算即可,以下是控制台输入后缀表达式来计算逆波兰的程序代码。(其中通过类模板定义的栈的相关操作代码在前一篇博客中,不再赘述。)
double ReverPolandCalculator()
{
string context;
Stack<double>S;
cout << "请输入您想进行计算的数字和运算符 中间以空格分开 以#结束" << endl;
int count = 0;
getline(cin, context);//得到用户输入的字符串
int move = 0;
char Number[10];
//数字的最大长度取10 这块没做异常抛出
//我寻思 谁也不能整10位数以上的运算把 他不lay么
while (context[move]!='#')
{
if (context[move] !=' ')
{
int pos = 0;
while (isdigit(context[move])|| context[move] == '.')//将数字取出来
{
//isdigit() 用来判断字符是否为数字
Number[pos] = context[move];
Number[pos + 1] = '\0';//这个写了是为了后面检测不会出错
pos++;
move++;
//也可直接写为
//Number[++pos] = '\0';
}
if (pos)
{
S.PushElem(atof(Number));
}
switch (context[move])
{
case '-':
{
double a = S.PopElem();
double b = S.PopElem();
S.PushElem(b - a);
break;
}
case '*':
{
double a = S.PopElem();
double b = S.PopElem();
S.PushElem(b * a);
break;
}
case '+':
{
double a = S.PopElem();
double b = S.PopElem();
S.PushElem(b + a);
break;
}
case '/':
{
double a = S.PopElem();
double b = S.PopElem();
S.PushElem(b / a);
break;
}
default:
break;
}
}
move++;
}
return S.GetTopElem();
}
接着是用户输入中缀表达式转为后缀表达式的代码,睡醒再敲哈哈哈哈哈哈哈哈哈哈💖
double ReverPolandCalculator(char * context)
//重载版本的 直接把中缀转后缀封装到一个测试函数里了 比较的奈斯
//但其实就是把用户输入的字符串换掉了鹅已拉~✨
{
Stack<double>S;
int move = 0;
char Number[10];//数字的最大长度取10
while (context[move]!='#')
{
if (context[move] !=' ')
{
int pos = 0;
while (isdigit(context[move])|| context[move] == '.')//将数字取出来
{
//isdigit() 用来判断字符是否为数字
Number[pos] = context[move];
Number[pos + 1] = '\0';
pos++;
move++;
//也可直接写为
//Number[pos++] = '\0';
}
if (pos)
{
S.PushElem(atof(Number));
}
switch (context[move])
{
case '-':
{
double a = S.PopElem();
double b = S.PopElem();
S.PushElem(b - a);
break;
}
case '*':
{
double a = S.PopElem();
double b = S.PopElem();
S.PushElem(b * a);
break;
}
case '+':
{
double a = S.PopElem();
double b = S.PopElem();
S.PushElem(b + a);
break;
}
case '/':
{
double a = S.PopElem();
double b = S.PopElem();
S.PushElem(b / a);
break;
}
default:
break;
}
}
move++;
}
return S.GetTopElem();
}
int Priority(char a)
{
switch (a)
{
case '+':
return 1;
break;
case '-':
return 1;
break;
case '*':
return 2;
break;
case '/':
return 2;
break;
default:
return 0;
break;
}
}
char* Turn2ReverPoland(string context,char *Output)
{
int i = 0;
Stack<char>S;
int move = 0;
while (context[i] != '\0')
{
if (isdigit(context[i])|| context[i]=='.')
{
Output[move] = context[i];
Output[move+1] = '\0';
move++;
if (isdigit(context[i+1])||context[i+1]=='.')
{
}
else
{
move++;
}
}
else
{
switch (context[i])
{
case ')':
{
while ('(' != S.GetTopElem())
{
char op1 = S.PopElem();
Output[move] = op1;
Output[++move] = '\0';
move++;
}
if ('(' == S.GetTopElem())
{
S.PopElem();
}
break;
}
case '(':
S.PushElem(context[i]);
break;
default:
{
int prio = Priority(context[i]);
if (0==S.GetLength())
{
S.PushElem(context[i]);
}
else
{
while (prio <= Priority(S.GetTopElem()))
{
char op1 = S.PopElem();
Output[move] = op1;
Output[++move] = '\0';
move++;
}
if (prio > Priority(S.GetTopElem()))
{
S.PushElem(context[i]);
}
break;
}
}
}
}
i++;
}
while (S.GetLength())
{
Output[move] = S.PopElem();
Output[++move] = '\0';
move++;
}
Output[move] = '#';
//a = Output;
//char *str = Output;
return Output;
}
然后这些结合食用,就能看见想要的效果拉!
不得不说 模板类真香 C++真香🍭
void ShowReverPoland(char* arr)
{
int move = 0;
while (arr[move]!='#')
{
cout << arr[move];
move++;
}
cout << endl;
}
void test10()
{
string context;
cout << "请输入待计算的表达式:回车结束" << endl;
getline(cin, context);
int i = 0;
char Output[100];
Turn2ReverPoland(context, Output);
cout << "逆波兰后的表达式为:" << endl;
ShowReverPoland(Output);
double a = ReverPolandCalculator(Output);
cout << "逆波兰后的计算结果为:"<<a << endl;
}
来个结果~