天天看點

用Qt實作的電腦

需求分析

子產品圖

用Qt實作的電腦

類圖

用Qt實作的電腦

核心算法

中綴表達式轉化為字尾表達式

規則:從左到右周遊中綴表達式(表達式運算符在兩數字之間,比如(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(,);
            if(!expression.isEmpty())
            {
                stack.push(expression.left());
                expression.remove(,);
            }

        }
        else
        {
            //遇到數字,直接輸出
            temp+=expression.left();
            expression.remove(,);
        }

    }
    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=;
    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()==)
            {
                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=;i<;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[]=createButtons("*");
    symbolButtons[]=createButtons("/");
    symbolButtons[]=createButtons("+");
    symbolButtons[]=createButtons("-");
    symbolButtons[]=createButtons(".");
    symbolButtons[]=createButtons("=");
    symbolButtons[]=createButtons("(");
    symbolButtons[]=createButtons(")");
    symbolButtons[]=createButtons(trUtf8("删除"));
    for(int i=;i<;i++)
    {
        symbolButtons[i]->setStyleSheet("font-weight:bold;font-size:30px;color:white;background-color:rgb(33,33,33)");
    }
    symbolButtons[]->setStyleSheet("font-size:20px;color:white;background-color:rgb(26,26,26)");
           

一開始我是這麼寫的,看了一下覺得還可以再優化一下,就成了下面這樣

QString buttonText[] = {"*","/","+","-",".","=","(",")"};
    for(int i=;i<;i++)
    {
        symbolButtons[i]=createButtons(buttonText[i]);
        symbolButtons[i]->setStyleSheet("font-weight:bold;font-size:30px;color:white;background-color:rgb(33,33,33)");
    }
    symbolButtons[]=createButtons(trUtf8("删除"));
    symbolButtons[]->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(,);
    if(text == QString("0"))
        rightLayout->addWidget(tb,,);
    else if(text == QString("("))
        rightLayout->addWidget(tb,,);
    else if(text == QString(")"))
        rightLayout->addWidget(tb,,);
    else if(text == QString(trUtf8("删除")))
        rightLayout->addWidget(tb,,);
    else if(text == QString("*"))
        rightLayout->addWidget(tb,,);
    else if(text == QString("/"))
        rightLayout->addWidget(tb,,);
    else if(text == QString("+"))
        rightLayout->addWidget(tb,,);
    else if(text == QString("-"))
        rightLayout->addWidget(tb,,);
    else if(text == QString("."))
        rightLayout->addWidget(tb,,);
    else if(text == QString("="))
        rightLayout->addWidget(tb,,);
    else
        rightLayout->addWidget(tb,(text.toInt()-)/+,(text.toInt()-)%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);
           

運作效果

用Qt實作的電腦

輸入表達式,包含三位數,小數,加減乘除,括号

用Qt實作的電腦

點選圖中紅色标注 等号 進行運算。

用Qt實作的電腦

紅色标注輸入框顯示運算結果。

用Qt實作的電腦

紅色标注顯示框為計算過程。

用Qt實作的電腦

點選紅色框框标注的切換按鈕切換顯示棧中資料變化情況

用Qt實作的電腦
用Qt實作的電腦

紅色框框标注顯示棧中資料變化情況,上下兩圖分别為中綴表達式轉字尾表達式和字尾表達式運算時的棧中資料變化情況。

源碼

源碼已上傳請點選 CSDN資源或Github下載下傳

代碼有問題的地方以及說錯的地方還請指出,謝謝!

有任何不解的地方請留言,很樂意為您解答。

歡迎轉載,但請附上原位址http://blog.csdn.net/jiaxingzheng/article/details/44240215,謝謝!

繼續閱讀