利用两个栈求解中缀表达式
基础没有小括号的版本
首先是最基础的只有 +、-、*、/ 功能的版本(实际再加 % ^ 运算都是一样的),并没有添加 (、) 进行运算限制
计算思路就是当前运算符与栈顶运算符进行比较,如果小于栈顶运算符的优先级,则说明应该先算栈顶的优先符;在只有 +、-、*、/ 运算,这个运算规则是很容易理解的
#include <iostream>
#include <stack>
#include <map>
using namespace std;
int getNum(string A, int length, int& startIndex);
// 运算符优先级 # < () < +- < */
void getRes(stack<int>& num, stack<char>& myOperator);
void printStack(stack<char> myOperator, stack<int> num);
int main()
{
stack<char> myOperator;
stack<int> num;
string A;
cin >> A;
int length = A.length();
int startIndex = 0;
map<char, int> mp;
mp.insert(map < char, int>::value_type('#', 0));
mp.insert(map < char, int>::value_type('(', 1));
mp.insert(map < char, int>::value_type(')', 1));
mp.insert(map < char, int>::value_type('+', 2));
mp.insert(map < char, int>::value_type('-', 2));
mp.insert(map < char, int>::value_type('*', 3));
mp.insert(map < char, int>::value_type('/', 3));
for (int i = 0; i < length; i++)
{
if (A[i] >= '0' && A[i] <= '9')
{
startIndex = i;
num.push(getNum(A, length, startIndex));
i = startIndex - 1;
}
else if (myOperator.empty() || mp[myOperator.top()] < mp[A[i]])
{
myOperator.push(A[i]);
}
else
{
getRes(num, myOperator);
myOperator.push(A[i]);
}
printStack(myOperator, num);
}
while (!myOperator.empty())
{
getRes(num, myOperator);
}
cout << num.top();
}
int getNum(string A, int length, int& startIndex)
{
int i;
for (i = startIndex; i < length; i++)
{
if (A[i] < '0' || A[1] > '9')
{
break;
}
}
string temp = A.substr(startIndex, i);
startIndex = i;
return atoi(temp.c_str());
}
void getRes(stack<int>& num, stack<char>& myOperator)
{
int num2 = num.top();
num.pop();
int num1 = num.top();
num.pop();
char ch = myOperator.top();
myOperator.pop();
switch (ch)
{
case '+':
num.push(num1 + num2);
break;
case '-':
num.push(num1 - num2);
break;
case '*':
num.push(num1 * num2);
break;
case '/':
num.push(num1 / num2);
break;
}
}
void printStack(stack<char> myOperator, stack<int> num)
{
stack<char> tempOperator = myOperator;
stack<int> tempNum = num;
int operatorSize = tempOperator.size();
int numSize = tempNum.size();
for (int i = 0; i < max(operatorSize, numSize); i++)
{
if (!tempOperator.empty())
{
cout << tempOperator.top() << "\t";
tempOperator.pop();
}
else
{
cout << " \t";
}
if (!tempNum.empty())
{
cout << tempNum.top();
tempNum.pop();
}
cout << endl;
}
cout << "------------------------------" << endl;
}
/*
测试数据一:
1+3*5*6/2
预期结果:
46
测试数据二:
1*4/2/2*5
预期结果:
5
测试数据三:
123+234
预期结果:
357
测试数据四:
5+3*12+4/4-8
预期结果:
34
*/
有小括号的版本
由于小括号的限制,导致需要先算小括号里面的,写法有了一些变化
这次会在遇到左括号时进行入栈,然后在遇到右括号时进行左括号的出栈,达到先算括号里面的功能
#include <iostream>
#include <stack>
#include <map>
using namespace std;
int getNum(string A, int length, int& startIndex);
// 运算符优先级 # < () < +- < */
void getRes(stack<int>& num, stack<char>& myOperator);
void printStack(stack<char> myOperator, stack<int> num);
int main()
{
stack<char> myOperator;
stack<int> num;
string A;
cin >> A;
int length = A.length();
int startIndex = 0;
map<char, int> mp;
mp.insert(map < char, int>::value_type('#', 0));
mp.insert(map < char, int>::value_type('(', 1));
mp.insert(map < char, int>::value_type(')', 1));
mp.insert(map < char, int>::value_type('+', 2));
mp.insert(map < char, int>::value_type('-', 2));
mp.insert(map < char, int>::value_type('*', 3));
mp.insert(map < char, int>::value_type('/', 3));
for (int i = 0; i < length; i++)
{
if (A[i] >= '0' && A[i] <= '9')
{
startIndex = i;
num.push(getNum(A, length, startIndex));
i = startIndex - 1;
}
else if (myOperator.empty() || mp[myOperator.top()] < mp[A[i]])
{
myOperator.push(A[i]);
}
else
{
if (A[i] == '(')
{
myOperator.push(A[i]);
}
else if (A[i] == ')')
{
while (myOperator.top() != '(')
{
getRes(num, myOperator);
}
myOperator.pop();
}
else
{
getRes(num, myOperator);
myOperator.push(A[i]);
}
}
printStack(myOperator, num);
}
while (!myOperator.empty())
{
getRes(num, myOperator);
printStack(myOperator, num);
}
cout << num.top();
}
int getNum(string A, int length, int& startIndex)
{
int i;
for (i = startIndex; i < length; i++)
{
if (A[i] < '0' || A[1] > '9')
{
break;
}
}
string temp = A.substr(startIndex, i);
startIndex = i;
return atoi(temp.c_str());
}
void getRes(stack<int>& num, stack<char>& myOperator)
{
int num2 = num.top();
num.pop();
int num1 = num.top();
num.pop();
char ch = myOperator.top();
myOperator.pop();
switch (ch)
{
case '+':
num.push(num1 + num2);
break;
case '-':
num.push(num1 - num2);
break;
case '*':
num.push(num1 * num2);
break;
case '/':
num.push(num1 / num2);
break;
}
}
void printStack(stack<char> myOperator, stack<int> num)
{
stack<char> tempOperator = myOperator;
stack<int> tempNum = num;
int operatorSize = tempOperator.size();
int numSize = tempNum.size();
for (int i = 0; i < max(operatorSize, numSize); i++)
{
if (!tempOperator.empty())
{
cout << tempOperator.top() << "\t";
tempOperator.pop();
}
else
{
cout << " \t";
}
if (!tempNum.empty())
{
cout << tempNum.top();
tempNum.pop();
}
cout << endl;
}
cout << "------------------------------" << endl;
}
/*
测试数据一:
5+3*(12+4)/4-8
预期结果:
9
*/
支持负数、%、^、和小数的版本
相较于小括号的版本遇到的主要的问题是负号的判断,其余的都只是简单的添加一些语句与修改数据类型和调用函数而已(实际有点难考虑,我设计为负号需要在小括号内使用,且紧靠左边,例如(-3*5) => -15 )
#include <iostream>
#include <stdio.h>
#include <stack>
#include <map>
#include <cmath>
using namespace std;
float getNum(string A, int length, int& startIndex);
// 运算符优先级 () < +- < */% < ^
void getRes(stack<float>& num, stack<char>& myOperator);
void printStack(stack<char> myOperator, stack<float> num);
int main()
{
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
stack<char> myOperator;
stack<float> num;
string A;
cin >> A;
int length = A.length();
int startIndex = 0;
map<char, int> mp;
mp.insert(map < char, int>::value_type('(', 1));
mp.insert(map < char, int>::value_type(')', 1));
mp.insert(map < char, int>::value_type('+', 2));
mp.insert(map < char, int>::value_type('-', 2));
mp.insert(map < char, int>::value_type('*', 3));
mp.insert(map < char, int>::value_type('/', 3));
mp.insert(map < char, int>::value_type('%', 3));
mp.insert(map < char, int>::value_type('^', 4));
for (int i = 0; i < length; i++)
{
bool flag = (A[i] >= '0' && A[i] <= '9') || (A[i] == '-' && A[i - 1] == '(' && (A[i + 1] >= '0' && A[i + 1] <= '9'));
if (flag)
{
startIndex = i;
num.push(getNum(A, length, startIndex));
i = startIndex - 1;
}
else if (myOperator.empty() || mp[myOperator.top()] < mp[A[i]])
{
myOperator.push(A[i]);
}
else
{
if (A[i] == '(')
{
myOperator.push(A[i]);
}
else if (A[i] == ')')
{
while (myOperator.top() != '(')
{
getRes(num, myOperator);
}
myOperator.pop();
}
else
{
getRes(num, myOperator);
myOperator.push(A[i]);
}
}
printStack(myOperator, num);
}
while (!myOperator.empty())
{
getRes(num, myOperator);
printStack(myOperator, num);
}
cout << num.top();
}
float getNum(string A, int length, int& startIndex)
{
bool isNegative = false;
if (A[startIndex] == '-')
{
isNegative = true;
}
bool isFirsAppear = true;
int i = isNegative ? startIndex + 1 : startIndex;
for (; i < length; i++)
{
if ((A[i] >= '0' && A[i] <= '9'))
{
continue;
}
else if (A[i] == '.' && isFirsAppear)
{
isFirsAppear = false;
continue;
}
break;
}
string temp = A.substr(startIndex, i);
startIndex = i;
return atof(temp.c_str());
}
void getRes(stack<float>& num, stack<char>& myOperator)
{
float num2 = num.top();
num.pop();
float num1 = num.top();
num.pop();
char ch = myOperator.top();
myOperator.pop();
switch (ch)
{
case '+':
num.push(num1 + num2);
break;
case '-':
num.push(num1 - num2);
break;
case '*':
num.push(num1 * num2);
break;
case '/':
num.push(num1 / num2);
break;
case '%':
num.push((int)num1 % (int)num2);
break;
case '^':
num.push(pow(num1, num2));
break;
}
}
void printStack(stack<char> myOperator, stack<float> num)
{
stack<char> tempOperator = myOperator;
stack<float> tempNum = num;
int operatorSize = tempOperator.size();
int numSize = tempNum.size();
for (int i = 0; i < max(operatorSize, numSize); i++)
{
if (!tempOperator.empty())
{
cout << tempOperator.top() << "\t";
tempOperator.pop();
}
else
{
cout << " \t";
}
if (!tempNum.empty())
{
cout << tempNum.top();
tempNum.pop();
}
cout << endl;
}
cout << "------------------------------" << endl;
}
/*
测试数据一:
5%2+3*(-12+4.3)/4-8^2
预期结果:
-68.775
测试数据二:
5%2+3*(-12+(-4.3*5))/4-8^2
预期结果:
-88.125
*/
结合Winform制作带界面的计算器(只写了支持小括号的版本)
主要是对C++程序的输入输出重定向与C#调用exe程序
#include <iostream>
#include <stdio.h>
#include <stack>
#include <map>
using namespace std;
int getNum(string A, int length, int& startIndex);
// 运算符优先级 # < () < +- < */
void getRes(stack<int>& num, stack<char>& myOperator);
void printStack(stack<char> myOperator, stack<int> num);
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
stack<char> myOperator;
stack<int> num;
string A;
cin >> A;
int length = A.length();
int startIndex = 0;
map<char, int> mp;
mp.insert(map < char, int>::value_type('#', 0));
mp.insert(map < char, int>::value_type('(', 1));
mp.insert(map < char, int>::value_type(')', 1));
mp.insert(map < char, int>::value_type('+', 2));
mp.insert(map < char, int>::value_type('-', 2));
mp.insert(map < char, int>::value_type('*', 3));
mp.insert(map < char, int>::value_type('/', 3));
for (int i = 0; i < length; i++)
{
if (A[i] >= '0' && A[i] <= '9')
{
startIndex = i;
num.push(getNum(A, length, startIndex));
i = startIndex - 1;
}
else if (myOperator.empty() || mp[myOperator.top()] < mp[A[i]])
{
myOperator.push(A[i]);
}
else
{
if (A[i] == '(')
{
myOperator.push(A[i]);
}
else if (A[i] == ')')
{
while (myOperator.top() != '(')
{
getRes(num, myOperator);
}
myOperator.pop();
}
else
{
getRes(num, myOperator);
myOperator.push(A[i]);
}
}
printStack(myOperator, num);
}
while (!myOperator.empty())
{
getRes(num, myOperator);
printStack(myOperator, num);
}
cout << num.top();
}
int getNum(string A, int length, int& startIndex)
{
int i;
for (i = startIndex; i < length; i++)
{
if (A[i] < '0' || A[1] > '9')
{
break;
}
}
string temp = A.substr(startIndex, i);
startIndex = i;
return atoi(temp.c_str());
}
void getRes(stack<int>& num, stack<char>& myOperator)
{
int num2 = num.top();
num.pop();
int num1 = num.top();
num.pop();
char ch = myOperator.top();
myOperator.pop();
switch (ch)
{
case '+':
num.push(num1 + num2);
break;
case '-':
num.push(num1 - num2);
break;
case '*':
num.push(num1 * num2);
break;
case '/':
num.push(num1 / num2);
break;
}
}
void printStack(stack<char> myOperator, stack<int> num)
{
stack<char> tempOperator = myOperator;
stack<int> tempNum = num;
int operatorSize = tempOperator.size();
int numSize = tempNum.size();
for (int i = 0; i < max(operatorSize, numSize); i++)
{
if (!tempOperator.empty())
{
cout << tempOperator.top() << "\t";
tempOperator.pop();
}
else
{
cout << " \t";
}
if (!tempNum.empty())
{
cout << tempNum.top();
tempNum.pop();
}
cout << endl;
}
cout << "------------------------------" << endl;
}
/*
测试数据一:
5+3*(12+4)/4-8
预期结果:
9
*/
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace Calculator_C__
{
public partial class 计算器 : Form
{
public 计算器()
{
InitializeComponent();
}
private void Calculate_Click(object sender, EventArgs e)
{
string input = Input.Text;
StreamWriter writer = new StreamWriter("input.txt");
writer.Write(input);
writer.Close();
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo("4.exe");
process.StartInfo = startInfo;
process.Start();
Thread.Sleep(1000);
StreamReader reader = new StreamReader("output.txt");
string line;
while ((line = reader.ReadLine()) != null)
{
Result.Text += line + "\n";
}
reader.Close();
}
}
}