此项目用到的主要有中缀表达式转后缀表达式,双栈法实现带括号的四则运算
中缀转后缀表达式:
思路:和中缀表达式的计算类似,只不过不用计算,把表达式输出即可
1.用字符数组存储整行输入的中缀表达式;
2.接着从字符数组的0位置开始判断字符,如果是数字,那就要判断后面是否是数字,如果是就不断扫描组成一个整数
(暂不考虑负数和小数),最终组成一个整数,然后输出这个数(因为不用计算,所以直接输出即可);
3.如果是左括号,直接进符号栈;
4.如果是操作运算符,与符号栈的栈顶元素比较优先级:如果高就压入栈;
低,就取出符号栈顶的元素输出;
接着,再判断符号栈顶的元素和当前的运算符号继续比较优先级,重复前面步骤,直到栈空或者当前的符号优先级高;
5.如果是右括号,把符号栈栈顶的元素取出,如果不是左括号,把取出的运算符输出,接着取符号栈栈顶的元素,直到符号栈
中取出的符号是左括号;
6.当扫描完字符数组时,判断符号栈是否为空:
不为空,把符号栈栈顶的元素取出,输出到窗口,直到符号栈为空。
双栈法:
思路:需要两个栈,一个用来存数字,一个用来存符号
定义一个指针index用来遍历表达式
遍历表达式,index指向数字时,将该数字压入数字栈
这里需要注意:指向的数字并非是一位数,可能是多位数
是多位数的情况下,则需要在指向的数字往后看一位,如果是数字,要进行拼接,得到两位数;
还需要再往后看一位,直到后一位是符号为止,才能将最终拼接出来的数压入数字栈
index指向符号时,则需要判断
①如果当前的符号栈为空,则直接压入符号栈
②如果指向的符号优先级大于符号栈顶符号的优先级,则直接压入符号栈
③如果指向的符号优先级小于或等于符号栈顶符号的优先级,则需要从数字栈中取出两个数,并在符号栈中取出一个符号,进行运算,将得到的结果压入数字栈,最后将指向的当前的符号压入符号栈
当表达式遍历结束,顺序从数字栈和符号栈中取出相应的数字和符号,并运算
最后在数字栈中只有一个数字,即表达式的最终结果
UI界面展示:
UI的实现代码:
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("计算器");
}
槽函数的实现:
void Widget::on_btn_clear_clicked() //清空
{
ui->le_show->clear();
infix.clear();
}
void Widget::on_btn_back_clicked() //退格
{
infix.remove(infix.length()-1,1);
ui->le_show->setText(infix);
}
void Widget::on_btn_1_clicked()
{
infix += "1";
ui->le_show->setText(infix);
}
void Widget::on_btn_0_clicked()
{
infix += "0";
ui->le_show->setText(infix);
}
void Widget::on_btn_point_clicked()
{
if(infix.lastIndexOf(".")>infix.lastIndexOf("+")||infix.lastIndexOf(".")>infix.lastIndexOf("-")||infix.lastIndexOf(".")>infix.lastIndexOf("*")||infix.lastIndexOf(".")>infix.lastIndexOf("/"))return;
if(infix.back()==")"||infix.back()=="("||infix.back()=="+"||infix.back()=="-"||infix.back()=="*"||infix.back()=="/"||infix.back()==".")return;
infix += ".";
ui->le_show->setText(infix);
}
void Widget::on_btn_add_clicked()
{
if(infix.back()=="("||infix.back()=="+"||infix.back()=="-"||infix.back()=="*"||infix.back()=="/"||infix.back()==".")return;
infix += "+";
ui->le_show->setText(infix);
}
void Widget::on_btn_sub_clicked()
{
if(infix.back()=="("||infix.back()=="+"||infix.back()=="-"||infix.back()=="*"||infix.back()=="/"||infix.back()==".")return;
infix += "-";
ui->le_show->setText(infix);
}
void Widget::on_btn_3_clicked()
{
infix += "3";
ui->le_show->setText(infix);
}
void Widget::on_btn_2_clicked()
{
infix += "2";
ui->le_show->setText(infix);
}
void Widget::on_btn_multiply_clicked()
{
if(infix.back()=="("||infix.back()=="+"||infix.back()=="-"||infix.back()=="*"||infix.back()=="/"||infix.back()==".")return;
infix += "*";
ui->le_show->setText(infix);
}
void Widget::on_btn_6_clicked()
{
infix += "6";
ui->le_show->setText(infix);
}
void Widget::on_btn_5_clicked()
{
infix += "5";
ui->le_show->setText(infix);
}
void Widget::on_btn_4_clicked()
{
infix += "4";
ui->le_show->setText(infix);
}
void Widget::on_btn_divide_clicked()
{
if( infix.back()=="("||infix.back()=="+"||infix.back()=="-"||infix.back()=="*"||infix.back()=="/"||infix.back()==".")return;
infix += "/";
ui->le_show->setText(infix);
}
void Widget::on_btn_9_clicked()
{
infix += "9";
ui->le_show->setText(infix);
}
void Widget::on_btn_8_clicked()
{
infix += "8";
ui->le_show->setText(infix);
}
void Widget::on_btn_7_clicked()
{
infix += "7";
ui->le_show->setText(infix);
}
void Widget::on_btn_right_clicked()
{
if(infix.back()=="("||infix.back()=="+"||infix.back()=="-"||infix.back()=="*"||infix.back()=="/"||infix.back()==".")return;
if(count1>count2){
count2++;
infix += ")";
ui->le_show->setText(infix);}
}
void Widget::on_btn_left_clicked()
{
if(infix.back()>="0"&&infix.back()<="9")return;
if(infix.back()==".")return;
count1++;
infix += "(";
ui->le_show->setText(infix);
}
核心算法的实现:
void Widget::on_btn_equal_clicked()// =
{
QChar j= infix.right(1).at(0);
if(count1!=count2||j=="+"||j=="-"||j=="*"||j=="/")
{
ui->le_show->setText("表达式错误");
return;
}
ui->text_history->clear();
optr.clear();
opnd.clear();
if(infix[0]=="-")
infix = "0" + infix;
if(infix.isEmpty())
return;
optr.push('='); //=置于栈底,级别最低
int i = 0;
double num,a,b;
char item,ch;
while(!optr.empty())
{
if(infix[i]=="0"||infix[i]=="1"||infix[i]=="2"||infix[i]=="3"||infix[i]=="4"||infix[i]=="5"||
infix[i]=="6"||infix[i]=="7"||infix[i]=="8"||infix[i]=="9"||infix[i]==".") //数字字符或者.,则拼接并入栈
{
num = jointNum(infix,i);
opnd.push(num); //数字入栈
}
else //操作符
{
item = optr.top();
switch(compare_priority(in_priority(item),out_priority(infix[i].toLatin1())))//比较运算符优先级,toLatin1:QChar->char
{
case -1:
{
optr.push(infix[i].toLatin1());//infix[i]优先级高,入栈
i++; //指向下一个字符
}
break;
case 0:
{
item = optr.pop(); //删除括号或者=
if(item!='=')
i++; //指向下一个字符
}
break;
case 1:
{
ch = optr.pop(); //infix[i]级别低,弹出一个运算符并弹出两个操作数进行运算后再压栈
a = opnd.pop();
b = opnd.pop();
opnd.push(calcualate_num(a,b,ch)); //运算后结果入栈
}
}
}
}
num = opnd.pop();
if(!opnd.empty())
qDebug()<<"error";
QString temp = infix + "="+ QString::number(num);
history_infix.push_back(temp);
de_weight(history_infix);
for(int i = 0;i<history_infix.size();i++)
{
ui->text_history->append(history_infix.at(i));
}
ui->le_show->setText(QString::number(num));
infix = QString::number(num);
}
运算符优先级判定及运算符栈和运算数栈的定义:
int Widget::in_priority(char ch)
{
int in;
switch(ch)
{
case '=':in = 0;break;
case '+':in = 3;break;
case '-':in = 3;break;
case '*':in = 5;break;
case '/':in = 5;break;
case '(':in = 1;break;
case ')':in = 6;break;
}
return in;
}
int Widget::out_priority(char ch)
{
int out;
switch(ch)
{
case '=':out = 0;break;
case '+':out = 2;break;
case '-':out = 2;break;
case '*':out = 4;break;
case '/':out = 4;break;
case '(':out = 6;break;
case ')':out = 1;break;
}
return out;
}
int Widget::compare_priority(int in, int out)
{
if(in<out)
return -1;
else if(in==out)
return 0;
else
return 1;
}
int Widget::calcualate_num(double num1, double num2, char oper)
{
switch(oper)
{
case '+':return num2+num1;
case '-':return num2-num1;
case '*':return num2*num1;
case '/':
{
if(num1 == 0)
{
QMessageBox::warning(this,"错误","除数为0!!!");
return 0;
}
return num2/num1;
}
}
}