需求分析
模块图
类图
核心算法
中缀表达式转化为后缀表达式
规则:从左到右遍历中缀表达式(表达式运算符在两数字之间,比如(2+1)3)的每个数字和符号,若是数字就输出,即成为后缀表达式(表达式运算符在数字之后,不包含括号,比如2 1+3 )的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
转化为后缀表达式方便计算(所有的计算按运算符出现的顺序,严格从左向右进行,不再考虑运算符的优先规则。)。
规则分解
- 遇到操作数:直接输出(添加到后缀表达式中)
- 栈为空时,遇到运算符,直接入栈
- 遇到左括号:将其入栈
- 遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。
- 遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈
- 最终将栈中的元素依次出栈,输出。
现在按规则将中缀表达式(2+1)*3转化为后缀表达式
首先是左括号,进栈
( |
然后是数字2 直接输出 2
接着是+号,进栈
+ |
( |
然后是数字1 直接输出在2后面 2 1
然后遇到右括号,栈中所有元素出栈,输出加号,左括号不输出 2 1 +
接着*号,进栈
* |
然后是数字3 直接输出 2 1 + 3
表达式结束,栈中元素出栈 输出号 2 1 + 3
代码
QStack<QString> stack;
QString temp;//数字输出
QStringList list;//全部输出
while(!expression.isEmpty())
{
if(expression.startsWith('+')||expression.startsWith('-')||expression.startsWith('*')||expression.startsWith('/')||expression.startsWith('(')||expression.startsWith(')'))
{
//遇到运算符及左右括号,可能进栈,出栈
if(!temp.isEmpty())
{
list.append(temp);
temp.clear();
}
//+-)优先级高于或等于其它运算符及左括号,遇到则使栈中元素弹出
if(expression.startsWith('+')||expression.startsWith('-')||expression.startsWith(')'))
{
while(!stack.isEmpty())
{
if(stack.top()==QString('('))
{
//栈顶为左括号,遇到右括号,直接让左括号出栈,不输出
if(expression.startsWith(')'))
{
stack.pop();
}
break;
}
else
{
//将栈中元素输出,直到栈顶为左括号
list.append(stack.pop());
}
}
}
if(expression.startsWith(')'))
expression.remove(0,1);
if(!expression.isEmpty())
{
stack.push(expression.left(1));
expression.remove(0,1);
}
}
else
{
//遇到数字,直接输出
temp+=expression.left(1);
expression.remove(0,1);
}
}
if(!temp.isEmpty())
list.append(temp);
while(!stack.isEmpty())
{
list.append(stack.pop());
}
计算后缀表达式
规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。
现在按规则计算后缀表达式 2 1 + 3 *
遇到数字2 进栈
2 |
遇到数字1 进栈
1 |
2 |
遇到+号 将处于栈顶的两个数字 1 2 出栈 进行加法运算 得结果为3 进栈
3 |
遇到数字3 进栈
3 |
3 |
遇到乘号* 将处于栈顶的两个数字3 3 进行乘法运算 得结果为9 结束。
代码
QString operand1;
QString operand2;
QString result;
int row=0;
while(!list.isEmpty())
{
if(list.startsWith("+"))
{
operand2 = stack.pop();
operand1 = stack.pop();
result = QString::number(operand1.toDouble()+operand2.toDouble());
stack.push(result);
}
else if(list.startsWith("-"))
{
operand2 = stack.pop();
operand1 = stack.pop();
result = QString::number(operand1.toDouble()-operand2.toDouble());
stack.push(result);
}
else if(list.startsWith("*"))
{
operand2 = stack.pop();
operand1 = stack.pop();
result = QString::number(operand1.toDouble()*operand2.toDouble());
stack.push(result);
}
else if(list.startsWith("/"))
{
operand2 = stack.pop();
if(operand2.toDouble()==0)
{
lineEdit->setText(trUtf8("除数不能为0"));
flag = true;
}
operand1 = stack.pop();
result = QString::number(operand1.toDouble()/operand2.toDouble());
stack.push(result);
}
else
{
stack.push(list.first());
}
list.removeFirst();
operand1.clear();
operand2.clear();
}
界面
部分代码
for(int i=0;i<10;i++)
{
digitButtons[i]=createButtons(QString::number(i));
digitButtons[i]->setStyleSheet("font-size:30px;color:white;background-color:rgb(71,71,71)");
//QPalette pal = digitButtons[i]->palette();
//pal.setColor(QPalette::Button,QColor(112,128,105));
//pal.setColor(QPalette::ButtonText,QColor(225,225,225));
//digitButtons[i]->setPalette(pal);
}
symbolButtons[0]=createButtons("*");
symbolButtons[1]=createButtons("/");
symbolButtons[2]=createButtons("+");
symbolButtons[3]=createButtons("-");
symbolButtons[4]=createButtons(".");
symbolButtons[5]=createButtons("=");
symbolButtons[6]=createButtons("(");
symbolButtons[7]=createButtons(")");
symbolButtons[8]=createButtons(trUtf8("删除"));
for(int i=0;i<8;i++)
{
symbolButtons[i]->setStyleSheet("font-weight:bold;font-size:30px;color:white;background-color:rgb(33,33,33)");
}
symbolButtons[8]->setStyleSheet("font-size:20px;color:white;background-color:rgb(26,26,26)");
一开始我是这么写的,看了一下觉得还可以再优化一下,就成了下面这样
QString buttonText[8] = {"*","/","+","-",".","=","(",")"};
for(int i=0;i<8;i++)
{
symbolButtons[i]=createButtons(buttonText[i]);
symbolButtons[i]->setStyleSheet("font-weight:bold;font-size:30px;color:white;background-color:rgb(33,33,33)");
}
symbolButtons[8]=createButtons(trUtf8("删除"));
symbolButtons[8]->setStyleSheet("font-size:20px;color:white;background-color:rgb(26,26,26)");
下面是createButtons函数及buttonClicked函数
QToolButton *MainWindow::createButtons(const QString &text)
{
QToolButton *tb = new QToolButton;
tb->setText(text);
connect(tb,SIGNAL(clicked()),this,SLOT(buttonClicked()));
tb->setFixedSize(60,83);
if(text == QString("0"))
rightLayout->addWidget(tb,4,1);
else if(text == QString("("))
rightLayout->addWidget(tb,0,0);
else if(text == QString(")"))
rightLayout->addWidget(tb,0,1);
else if(text == QString(trUtf8("删除")))
rightLayout->addWidget(tb,0,3);
else if(text == QString("*"))
rightLayout->addWidget(tb,1,3);
else if(text == QString("/"))
rightLayout->addWidget(tb,2,3);
else if(text == QString("+"))
rightLayout->addWidget(tb,3,3);
else if(text == QString("-"))
rightLayout->addWidget(tb,4,3);
else if(text == QString("."))
rightLayout->addWidget(tb,4,0);
else if(text == QString("="))
rightLayout->addWidget(tb,4,2);
else
rightLayout->addWidget(tb,(text.toInt()-1)/3+1,(text.toInt()-1)%3);
return tb;
}
void MainWindow::buttonClicked()
{
if(flag == true)
{
lineEdit->clear();
flag = false;
}
QString expression = lineEdit->text();
QToolButton *tb = qobject_cast<QToolButton *>(sender());
QString text = tb->text();
if(text == QString(trUtf8("删除")))
lineEdit->backspace();
else if(text == QString("("))
{
lineEdit->cursorBackward(true);
QString leftLetter = lineEdit->selectedText();
if(leftLetter == QString("*")||leftLetter == QString("/")||leftLetter == QString("+")||leftLetter == QString("-"))
lineEdit->setText(expression+=text);
else
{
lineEdit->setText(expression);
return;
}
}
else if(text == QString(")"))
{
lineEdit->cursorBackward(true);
QString leftLetter = lineEdit->selectedText();
int countLeft=expression.count("(");
int countRight=expression.count(")");
if(leftLetter == QString("*")||leftLetter == QString("/")||leftLetter == QString("+")||leftLetter == QString("-")||leftLetter == QString(".")||leftLetter == QString("(")||countLeft<=countRight)
lineEdit->setText(expression);
else
lineEdit->setText(expression+=text);
}
else if(text == QString("*")||text == QString("/")||text == QString("+")||text == QString("-")||text == QString("."))
{
lineEdit->cursorBackward(true);
QString leftLetter = lineEdit->selectedText();
if(leftLetter == QString("*")||leftLetter == QString("/")||leftLetter == QString("+")||leftLetter == QString("-")||leftLetter == QString(".")|| leftLetter.isEmpty() )
{
lineEdit->setText(expression);
return;
}
else
lineEdit->setText(expression+=text);
}
else if(text == QString("="))
calculate();
else
lineEdit->setText(expression+=text);
}
计算器输入框选用QLineEdit类来实现,可以用键盘输入表达式,不过为了防止用户输入错误的信息,通过正则表达式来限制输入的内容只能为数字,小数点,加减乘除号和括号,而字母和其它符号将通通不被接受,不予输入!
QRegExp regExp("[0-9+*/()-.]*");
QRegExpValidator *validator =new QRegExpValidator(regExp,this);
lineEdit->setValidator(validator);
运行效果
输入表达式,包含三位数,小数,加减乘除,括号
点击图中红色标注 等号 进行运算。
红色标注输入框显示运算结果。
红色标注显示框为计算过程。
点击红色框框标注的切换按钮切换显示栈中数据变化情况
红色框框标注显示栈中数据变化情况,上下两图分别为中缀表达式转后缀表达式和后缀表达式运算时的栈中数据变化情况。