Bootstrap

数据结构-计算器实验报告

一、实验目的和要求

1. 设计并实现计算器。

要求:在课后作业-03、课后作业-05的作业内容基础上
(1)增加图形交互功能。
(2)增加3个逻辑运算符 &&、||、 !,并能处理逻辑运算符和算术运算符的混合运算。
(3)增加容错功能,能进行异常处理。

二、实验环境

Qt 5.9

三、实验内容

在课后作业-03、课后作业-05的作业内容基础上
(1)增加图形交互功能。
(2)增加3个逻辑运算符 &&、||、 !,并能处理逻辑运算符和算术运算符的混合运算。
(3)增加容错功能,能进行异常处理。

四、实验过程

用文字、图(流程图等)、表格等方式记录实验过程中分析、设计工作。

4.1 任务定义和问题分析

实验第一个要求是添加三个逻辑运算符,还是原来的套路,比较运算符之间的优先级来进行计算。
第二个要求是增加图形界面,本来打算使用MFC编写,可是后来发现Qt要简单的多,最终就用Qt编写。
第三个要求是增加容错,应该就是在计算之前检查一下表达式是否有错误,防止程序崩掉。

4.2 数据结构的选择和概要设计

数据结构选择用栈
采用运算符优先级比较来计算表达式,设置一全局变量QString line来保存表达式,按下相应的按键后,将对应的符号添加到line中,按下等于号后,先检查一下表达式是否有误,然后进行计算,显示结果。

4.3 详细设计

1.输入表达式

	为了将每一个符号添加到line中,设置void add_and_update()函数,将其与每个按键的信号相连,及每按一个键都会调用此函数,利用sender()函数来判断是哪一个按键发送的信号,将其对应的符号添加到line中。

2.计算输入的表达式

	这里用了一个信号可以对应对个槽的机制,将‘=’按键与两个槽链接void add_and_update()和void caculate(),由于链接顺序不同,会先调用void add_and_update()将‘#’添加到line中;再调用void caculate()计算表达式。

3.容错

	计算表达式前,先对表达式进行检查,若表达式有错弹出报错窗口并结束程序。
	计算表达式时,若出现除数为零的情况,弹出报错窗口,结束程序。
	计算过程中,若出现num栈为空但char_n栈不为空的情况,弹出报错窗口,结束程序。

4.逻辑运算符的计算:

	与和或通过运算符优先级的比较来计算;
	非直接在入栈计算,检测到符号“!”后,在num栈中取出一数,计算即可。

QString line; 用来保存用于计算的表达式。
QString line0; 用来保存用于显示的表达式。
QString history; 用来保存曾经正确计算的表达式,并将其显示出来。
QStack char_n; 用来保存字符。
QStack num; 用来保存数字。
QString s; 计算时将line赋值给它。
double result; 最后计算的结果。
void add_and_update(); 将运算符添加到line中。
void caculate(); 计算表达式。
bool check(); 检查表达式是否有误。
int getindex(char i); 得到对应字符的下标。
char getpriority(char i, char j); 通过下标来获取字符的优先级。
int hextobin(int i,int* n); 将十进制数转为二进制数。
int bintohex(int *p,int j) 将二进制数转为十进制。
int or_num(int j,int k); 对1,0进行或运算。
int and_num(int j,int k); 对1,0进行与运算。
int o_r(int j,int k); 对两个十进制数进行或运算。
int a_nd(int j,int k); 对两个十进制数进行与运算。
double caculator(char i, double j, double k);计算双目运算符

五、测试及结果分析

对各种数据运行程序和算法的结果记录和分析,并对错误所作的修改和结果。

5.1 实验数据

1+8/4-1!
5|8
9&(5+3)
9&1!
5.83.2-3
9/(4+8-12)
8
-5

5.2 结果及分析

六、实验收获

熟悉了Qt的使用,对Qt图形界面有了一定的了解

七、附录(源代码)

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
protected slots:
    void add_and_update();
    void caculate();
private:
    Ui::Widget *ui;
};

#endif // WIDGET_H


main.h

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include<Qstack>
#include<QString>
#include<iostream>
#include<cmath>
#include<QMessageBox>
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(ui->number0,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->number1,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->number2,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->number3,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->number4,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->number5,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->number6,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->number7,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->number8,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->number9,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->jia,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->jian,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->cheng,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->chu,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->zuokuohao,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->youkuohao,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->dengyu,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->dengyu,SIGNAL(clicked(bool)),this,SLOT(caculate()));
    connect(ui->c,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->shanchu,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->And,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->Not,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->Or,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->dian,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
    connect(ui->clearhistory,SIGNAL(clicked(bool)),this,SLOT(clear()));
    setFixedSize(this->width(),this->height());//禁止改变窗体大小
}
Widget::~Widget()
{
    delete ui;
}
QString line;
QString line0;
QString history;
QStack<char> char_n;
QStack<double> num;
QString s;
double result;
bool check()
{
    QString error[8]={"/","*","+","-","&","|",")","!"};
    QString error2[67]={"|&","&|","!|","!&","&-","&+","&*","&/","|+","|-","|*","|/","+&","+|","-&","-|","/|",
                        "/&","*&","*|","/*","*/","+-","-+","/-","-/","+/","/+","*+","+*","-*","*-","-)","(-",
                        "(+","+)","/)","(/","*)","(*","+-","-+","--","++","//","**","&&","||","!!","-.","+.",
                        "/.","*.","!.","&.","|.",".-",".+","./",".*",".!",".&",".|",".(",".)","(.",")."};
    for(int i=0;i<8;i++)
        if(line0.startsWith(error[i]))
            return false;
    for(int i=0;i<67;i++)
        if(line0.contains(error2[i],Qt::CaseSensitive))
            return false;
    return true;
}
int getindex(char i)
{
    switch (i)
    {
    case '+':
            return 0;
        case '-':
            return 1;
        case '*':
            return 2;
        case '/':
            return 3;
        case '(':
            return 4;
        case ')':
            return 5;
        case '&':
            return 6;
        case '|':
            return 7;
        case '#':
            return 8;
        default:
            return -1;
    }
}
char getpriority(char i, char j)
{
    const char data[][9] =
           {
               {'>', '>', '<', '<', '<', '>', '>', '>', '>'},
               {'>', '>', '<', '<', '<', '>', '>', '>', '>'},
               {'>', '>', '>', '>', '<', '>', '>', '>', '>'},
               {'>', '>', '>', '>', '<', '>', '>', '>', '>'},
               {'<', '<', '<', '<', '<', '=', '<', '<', '0'},
               {'>', '>', '>', '>', '0', '>', '>', '>', '>'},
               {'<', '<', '<', '<', '<', '>', '>', '>', '>'},
               {'<', '<', '<', '<', '<', '>', '<', '>', '>'},
               {'<', '<', '<', '<', '<', '0', '<', '<', '='},
           };
    int c = getindex(i);
    int d = getindex(j);
    return data[c][d];
}
int hextobin(int i,int* n)
{
    int j = 0;
    while (i)
    {
        n[j] = i % 2;
        i /= 2;
        j++;
    }
    return j;
}
int or_num(int j,int k)
{
    if (j==1||k==1)
    {
        return 1;
    }
    return 0;
}
int and_num(int j,int k)
{
    if (j==1&&k==1)
    {
        return 1;
    }
    return 0;
}
int bintohex(int *p,int j)
{
    int n = 0;
    for (int i = 0; i < j; i++)
    {
        if (p[i]==1)
            n += pow(2, i);
    }
    return n;
}
int o_r(int j,int k)
{
    int n1[1000]={0}, n2[1000]={0};
    int pos = hextobin(j, n1);
    int pos2 = hextobin(k, n2);
    if(pos>=pos2)
        pos2=pos;
    else {
        pos=pos2;
    }
    int num[pos];
    int h = 0;
    for (int i = 0; i <pos; i++)
    {
        num[h] = or_num(n1[i], n2[i]);
        ++h;
    }
    return bintohex(num,pos);
}
int a_nd(int j,int k)
{
    int n1[1000]={0}, n2[1000]={0};
    int pos = hextobin(j, n1);
    int pos2 = hextobin(k, n2);
    if(pos>=pos2)
        pos2=pos;
    else {
        pos=pos2;
    }
    int num[pos];
    int h = 0;
    for (int i = 0; i <pos; i++)
    {
        num[h] = and_num(n1[i], n2[i]);
        ++h;
    }
    return bintohex(num,pos);
}
double caculator(char i, double j, double k)
{
    switch (i)
    {
    case '+':
        return j + k;
    case '-':
        return j - k;
    case '*':
        return j * k;
    case '/':
        if(k==0)
            return 1e10;
        return j / k;
    case '|':
        return o_r(j,k);
    case '&':
        return a_nd(j,k);
    default:
        return 1e10;
    }
}

void Widget::caculate()
{
    if(!check())
        QMessageBox::critical(this,"错误","输入的表达式有误!");
    else
    {
    int i = 0;
    char_n.push('#');
    while (!s.isEmpty())
    {
        double data = 0;
        bool is_data=false;
        while (s[i].isDigit())
        {
            is_data=true;
            QString m=s.mid(0,1);
            data = data * 10 + m.toInt();
            s.remove(0,1);
            if(s[i]==".")
            {
                s.remove(0,1);
                int pos=0;
                int dex=0;
                while (s[i].isDigit())
                {
                    QString mn=s.mid(0,1);
                    pos = pos * 10 + mn.toInt();
                    dex++;
                    s.remove(0,1);
                }
                data+=pos/pow(10,dex);
            }
        }

        if (is_data)
            num.push(data);
        if (s[i]=='!')
        {
            s.remove(0,1);
            data=num.top();
            num.pop();
            num.push(!data);
         }
        if (!s[i].isDigit() )
        {
            char b = char_n.top();
            char priority;
            QString m=s.mid(0,1);
            QChar *n=new QChar[1];
            n=m.data();
            char l;
            l=n->toLatin1();
            priority = getpriority(b, l);
            switch (priority)
            {
            case '<':
                char_n.push(l);
                s.remove(0,1);
                break;
            case '=':
                char_n.pop();
                s.remove(0,1);
                break;
            case '>':
                double q = num.top();
                num.pop();
                if(num.empty())
                {
                    QMessageBox::critical(this,"错误","输入的表达式有误!");
                    return;
                }
                double w = num.top();
                num.pop();
                if(caculator(b, w, q)!=1e10)
                    num.push(caculator(b, w, q));
                else
                {
                    QMessageBox::warning(this,"警告","分母不能为零!");
                    return;
                }
                char_n.pop();
                break;
            }
        }
    }
    result = num.top();
    num.pop();
    history+=line;
    history+="=";
    history+=(QString::number(result));
    history+="\n";
    ui->textBrowser->setText(history);
    ui->lineEdit->setText(QString::number(result));
    }
}


void Widget::add_and_update()
{
    QPushButton *object=qobject_cast<QPushButton *>(sender());
    QString name=object->objectName();
    if(name=="number1")
    {
        line+="1";
        line0+="1";
        ui->label->setText(line);
    }
    if(name=="number2")
    {
        line+="2";
        line0+="2";
        ui->label->setText(line);
    }
    if(name=="number3")
    {
        line+="3";
        line0+="3";
        ui->label->setText(line);
    }
    if(name=="number4")
    {
        line+="4";
        line0+="4";
        ui->label->setText(line);
    }
    if(name=="number5")
    {
        line+="5";
        line0+="5";
        ui->label->setText(line);
    }
    if(name=="number6")
    {
        line+="6";
        line0+="6";
        ui->label->setText(line);
    }
    if(name=="number7")
    {
        line+="7";
        line0+="7";
        ui->label->setText(line);
    }
    if(name=="number8")
    {
        line+="8";
        line0+="8";
        ui->label->setText(line);
    }
    if(name=="number9")
    {
        line+="9";
        line0+="9";
        ui->label->setText(line);
    }
    if(name=="number0")
    {
        line+="0";
        line0+="0";
        ui->label->setText(line);
    }
    if(name=="chu")
    {
        line0+="/";
        line+="÷";
        ui->label->setText(line);
    }
    if(name=="cheng")
    {
        line0+="*";
        line+="×";
        ui->label->setText(line);
    }
    if(name=="jia")
    {
        line+="+";
        line0+="+";
        ui->label->setText(line);
    }
    if(name=="jian")
    {
        line+="-";
        line0+="-";
        ui->label->setText(line);
    }
    if(name=="And")
    {
        line+="&&";
        line0+="&";
        ui->label->setText(line);
    }
    if(name=="Not")
    {
        line+="!";
        line0+="!";
        ui->label->setText(line);
    }
    if(name=="Or")
    {
        line+="||";
        line0+="|";
        ui->label->setText(line);
    }
    if(name=="zuokuohao")
    {
        line+="(";
        line0+="(";
        ui->label->setText(line);
    }
    if(name=="youkuohao")
    {
        line+=")";
        line0+=")";
        ui->label->setText(line);
    }
    if(name=="dian")
    {
        line+=".";
        line0+=".";
        ui->label->setText(line);
    }
    if(name=="shanchu")
    {
        line.chop(1);
        line0.chop(1);
        ui->label->setText(line);
    }
    if(name=="c")
    {
        line=line0="";
        ui->label->setText(line);
        ui->lineEdit->setText("");
    }
    if(name=="dengyu")
    {
        s=line0+"#";
    }
}
void Widget::clear()
{
    history="";
    ui->textBrowser->setText(history);
}


;