C Windows Form簡易計算器實現(中)

2022-05-06 17:39:06 字數 3931 閱讀 3487

昨天花了一天的時間弄計算器。也算是做出來了,還是簡易的(懷疑猿生!!)。在此先感謝昨天被我騷擾的朋友。

先貼一張介面看看

其實健壯性還是挺差的,使用者體驗也是極差的。比如說使用者輸入了不合理表示式子,我就直接丟擲乙個異常完事了,因為要在原來的演算法裡加判斷實在暈亂。所以趁熱打鐵,希望在寫部落格的時候再把思路理理,完善不足。

思路一:

因為計算的是四則混合運算,比如2*6-4/(2+3)。我們最開始得到的是乙個表示式字串,計算機是不會幫你計算的。而四則混合運算有優先等級的計算,那麼該怎麼計算呢?於是問了問度娘,度娘說你可以用逆波蘭式計算。於是我二話不說看了看逆波蘭式子,果然高明。下面是貼一下逆波蘭式計算步驟:

///

///使用逆波蘭表示法求四則混合運算

///首先,需要兩個棧

///棧s1用於臨時儲存運算子(含乙個結束符號),此運算子在棧內遵循越往棧頂優先順序越高的原則;

///棧s2用於輸入逆波蘭式;

///為方便起見,棧s1需要放入乙個優先順序最低的運算子,在這裡假定為「#」;

///讀取表示式入棧的步驟

///1.若x是運算元,則分析出完整的運算數,壓入棧s2;

///2.若x是運算子,則分情況而定:

///若x是『(』,則直接壓入棧s1

///若x是『)』,則將距離棧s1棧頂的最近的『(』之間的運算子,逐個出棧,依次壓入棧s2,此時拋棄『(』

///若x是除了『(』和『)』以外的運算子,則再分如下情況

///若當前的棧頂元素是『(』,則直接將x壓入棧s1

///若當前的棧頂元素不是『(』,則將x與棧s1的棧頂元素進行對比,如果優先順序比較高,則壓入棧,如果優先順序低,則把棧s1的棧頂元素彈出壓入棧s2,直到棧s1的棧頂元素優先順序低於x,

///或則棧s2的棧頂運算子為『(』,此時再將x壓入棧s1

///3.進行完以上操作之後,檢查棧s1是否為空,若不為空,則將棧中元素依次彈出並壓入棧s2中。

///

把上面的2*6-4/(2+3)轉成逆波蘭式是這樣的:-/+324*62。注意,轉換完之後的逆波蘭式是沒有括號的。

思路二:

首先想到的是寫乙個函式,實現這一轉換。但是在寫的時候會發現,①會用到判斷是否是運算元還是操作符,②以及符號的優先順序。因為符號很多,寫在乙個判斷裡,**看起來會很長,所以就先把這兩個判斷寫成函式,以方便使用,增強**可讀性。

①判斷是數字還是符號函式如下:

//

//判斷是運算元還是操作符

//static

bool isnumber(string

str)

//

//定義優先等級,數字越大,優先等級越高

//static

void

definepriority()

然後接著寫轉換逆波蘭式的函式:

//

//接受乙個字串陣列,轉逆波蘭式子

//public

void reversetopolish(string

str)

else

if (dic[str[i]] == 6) //

如果是「)」,將棧頂元素依次壓入棧2,直到遇到「(」

stack1.pop();

//移除棧頂元素「(」

}

else

if (dic[str[i]] == 5 || dic[str[i]] == 4) //

除了「(」和「)」的情況

//若當前的棧頂元素不是『(』,則將x與棧s1的棧頂元素進行對比,如果優先順序比較高,則壓入棧

//如果不是,則把棧s1的棧頂元素彈出壓入棧s2,直到棧s1的棧頂元素優先順序低於x

else

stack1.push(str[i]);}}

//end else if

}//end else

}//end for

//進行完以上操作,檢查棧1是否為「#」,不是,則把棧頂元素依次壓入棧2

while (stack1.peek() != "#"

)

}catch

}//檢查下是否正確

foreach (var item in

stack2)

console.write(item);

console.writeline();

}

下面貼下整個類的**:

using

system;

using

system.collections.generic;

using

system.linq;

using

system.text;

using

system.threading.tasks;

namespace

簡易計算器

////

接受乙個字串陣列,轉逆波蘭式子

//public

void reversetopolish(string

str)

else

if (dic[str[i]] == 6) //

如果是「)」,將棧頂元素依次壓入棧2,直到遇到「(」

stack1.pop();

//移除棧頂元素「(」

}

else

if (dic[str[i]] == 5 || dic[str[i]] == 4) //

除了「(」和「)」的情況

//若當前的棧頂元素不是『(』,則將x與棧s1的棧頂元素進行對比,如果優先順序比較高,則壓入棧

//如果不是,則把棧s1的棧頂元素彈出壓入棧s2,直到棧s1的棧頂元素優先順序低於x

else

stack1.push(str[i]);}}

//end else if

}//end else

}//end for

//進行完以上操作,檢查棧1是否為「#」,不是,則把棧頂元素依次壓入棧2

while (stack1.peek() != "#"

)

}catch

}//檢查下是否正確

foreach (var item in

stack2)

console.write(item);

console.writeline();

}////

判斷是運算元還是操作符

//private

bool isnumber(string

str)

////

定義優先等級,數字越大,優先等級越高

//private

void

definepriority()}}

view code

筆者已經檢測過,邏輯是沒有問題的。總之我真的是寫了很久,因為在寫的時候會遇到如下的問題:就是當接受了加括號的一元運算子比如:1+(-2)。轉換得到的式子是不能正確計算的。

下次的博文我會分享解決上述問題的方法以及筆者自己的關於如何判斷使用者是否輸入正確的式子的方法

tip:關於這些邏輯性比較強的**,可能寫過一段時間到回去看就會看不懂了。所以,筆者的經驗是:寫的時候一定要嚴謹,想周到點。寫完如果不確定是否正確,就進行測試,親測幾次沒問題之後就不要管它了,把它縮起來,以後拿來用就好。寫的時候注釋一定要詳細點,萬一要到回去看呢!!!!

C Windows Form 假死處理

1,使用 taskfactory.startnew 另起task去執行耗時的任務,引數action public delegate void action 型別,乙個無參無返回值的方法。task.factory.startnew void timeconsumingmehtod 2,使用thread...

C WindowsForm操作MySql資料庫

1 c 提供運算元據庫技術 ado技術 2 運算元據庫步驟 連線資料庫 要先開啟允許遠端連線設定 1 定義連線資料庫字串 sql server 動態鏈結庫 using system.data.sqlclient string constr server uid root pwd 1365756916...

C Windows Form 重新整理父窗體

第一種方法 用委託,form2和form3是同一組 form2 c using system using system.collections.generic using system.componentmodel using system.data using system.drawing usi...