這是中國大學慕課移動終端應用開發的網課作業7,我會持續更新我的作業,如果有需要關注一下吧
說明
1.本計算器利用逆波蘭式能實現加減乘除複合運算
2.第一個數字輸入小數點能自動補全爲 0.
3.能檢測重複輸入小數點情況
4.能檢測式子語法正確情況
如果發現bug,或者有優化方案,可評論或私信聯繫我
博客中用到的數據結構鏈棧和鏈隊,在棧的java實現和隊的java實現這兩篇博文中。
界面展示
代碼部分
佈局文件 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:shrinkColumns="*"
android:stretchColumns="*"
android:background="@color/blue">
<TableRow>
<EditText
android:id="@+id/edit_show"
android:layout_height="100dp"
android:layout_span="4"
android:background="@color/white"
android:gravity="right"
android:textSize="40dp"
android:paddingTop="20dp"
android:layout_margin="10dp"/>
</TableRow>
<TableRow>
<Button
android:text="C"
android:onClick="clean"
style="@style/symbol"
android:background="@color/red"
/>
<Button
android:text="DEL"
style="@style/symbol"
android:onClick="delete"
android:layout_span="2"
/>
<Button
android:id="@+id/division"
android:text="/"
android:onClick="addFormula"
style="@style/symbol"
/>
</TableRow>
<TableRow>
<Button
android:id="@+id/number7"
android:text="7"
android:onClick="addFormula"
style="@style/number"
/>
<Button
android:id="@+id/number8"
android:text="8"
android:onClick="addFormula"
style="@style/number"
/>
<Button
android:id="@+id/number9"
android:text="9"
android:onClick="addFormula"
style="@style/number"
/>
<Button
android:id="@+id/multiplication"
android:text="*"
android:onClick="addFormula"
style="@style/symbol"
/>
</TableRow>
<TableRow>
<Button
android:id="@+id/number4"
android:text="4"
android:onClick="addFormula"
style="@style/number"
/>
<Button
android:id="@+id/number5"
android:text="5"
android:onClick="addFormula"
style="@style/number"
/>
<Button
android:id="@+id/number6"
android:text="6"
android:onClick="addFormula"
style="@style/number"
/>
<Button
android:id="@+id/add"
android:text="+"
android:onClick="addFormula"
style="@style/symbol"
/>
</TableRow>
<TableRow>
<Button
android:id="@+id/number1"
android:text="1"
android:onClick="addFormula"
style="@style/number"
/>
<Button
android:id="@+id/number2"
android:text="2"
android:onClick="addFormula"
style="@style/number"
/>
<Button
android:id="@+id/number3"
android:text="3"
android:onClick="addFormula"
style="@style/number"
/>
<Button
android:id="@+id/sub"
android:text="-"
android:onClick="addFormula"
style="@style/symbol"
/>
</TableRow>
<TableRow>
<Button
android:id="@+id/number0"
android:text="0"
android:onClick="addFormula"
style="@style/number"
android:layout_span="2"
/>
<Button
android:id="@+id/number_point"
android:text="."
android:onClick="addFormula"
style="@style/number"
/>
<Button
android:text="="
android:onClick="equal"
style="@style/symbol"
/>
</TableRow>
</TableLayout>
主題邏輯 MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.example.course8.model.LinkQueue;
import com.example.course8.model.LinkStack;
public class MainActivity extends AppCompatActivity {
private EditText mEditTextShow; //用於顯示的編輯框
private String strFormula = ""; //用於記錄算式
private boolean isFirstChar = true; //記錄判斷是不是第一個字符
private String tempNumber = "";//用於記錄一個數字,爲了判斷是否連續輸入小數點
private boolean newCalc = true;//用於記錄是否是新的一輪計算
private void init(){
mEditTextShow = findViewById(R.id.edit_show);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
//執行按到非功能鍵的時候執行的操作
public void addFormula(View v){
if (newCalc){//新一輪計算
cleanCalc();
newCalc = false;
}
String value = "";
switch(v.getId()){
case R.id.number0:
value = "0";
break;
case R.id.number1:
value = "1";
break;
case R.id.number2:
value = "2";
break;
case R.id.number3:
value = "3";
break;
case R.id.number4:
value = "4";
break;
case R.id.number5:
value = "5";
break;
case R.id.number6:
value = "6";
break;
case R.id.number7:
value = "7";
break;
case R.id.number8:
value = "8";
break;
case R.id.number9:
value = "9";
break;
case R.id.number_point:
value = ".";
break;
case R.id.sub:
value = "-";
break;
case R.id.add:
value = "+";
break;
case R.id.multiplication:
value = "*";
break;
case R.id.division:
value = "/";
break;
}
//如果是第一個符號
if (isFirstChar){
if (isNumber(value)){//如果是數字
if (value.equals(".")){ //如果是小數點
strFormula = "0.";
}else {
strFormula = value; //添加進式子
}
tempNumber = strFormula;
isFirstChar = false;
}else{ //是運算符
if (value.equals("+")||value.equals("-")){ //加減默認是正負號
strFormula = "0"+value;
isFirstChar = false;
}else {//是乘除,不符合
Toast.makeText(MainActivity.this,value+"不可放在式子最前端",Toast.LENGTH_SHORT).show();
}
}
mEditTextShow.setText(strFormula); //顯示在界面上
}else {//不是第一個字符
//判斷符不符合規則
if (isNumber(value)){//如果是數字
if (value.equals(".")){
if (tempNumber.indexOf(".")>-1){//已經有小數點了
Toast.makeText(MainActivity.this,"不可重複放置小數點",Toast.LENGTH_SHORT).show();
}else if (isOperator(getLastStr(strFormula))){
Toast.makeText(MainActivity.this,"運算符後不可放置小數點",Toast.LENGTH_SHORT).show();
}else {
strFormula += ".";
tempNumber += ".";
}
}else { //不是小數點
strFormula += value;
tempNumber += value;
}
}else {//是符號
if (isOperator(getLastStr(strFormula))){//如果式子最後一個字符是符號
Toast.makeText(MainActivity.this,"算術符號不符規則",Toast.LENGTH_SHORT).show();
}else {
strFormula += value; //增加式子
tempNumber="";//重置數字暫存
}
}
//更新ui
mEditTextShow.setText(strFormula);
}
}
//按到等於鍵
public void equal(View v) throws Exception {
if (newCalc){//新一輪計算
cleanCalc();
newCalc = false;
}
//判斷輸入的式子是否合法
if (isLegal(strFormula)){
//獲取式子的中綴表達式的隊列
LinkQueue infixQueue = getInfixQueue(strFormula);
//獲取後綴表達式
LinkQueue suffixQueue = getSuffixQueue(infixQueue);
//計算
LinkStack tempStack = new LinkStack(); //中間棧
int length = suffixQueue.length();
for(int i = 0;suffixQueue != null && i < length;i++){
String c = (String) suffixQueue.poll();//從後綴表達式中取出第一個
if(isOperator(c)){//當爲操作符的時候
//取出兩個操作數
double d2 = Double.valueOf(tempStack.pop().toString());
double d1 = Double.valueOf(tempStack.pop().toString());
double d3 = 0;
if(c.equals("+")){
d3 = d1 + d2;
}else if(c.equals("-")){
d3 = d1 - d2;
}else if(c.equals("*")){
d3 = d1 * d2;
}else if(c.equals("/")){
if (d2==0){
Toast.makeText(MainActivity.this,"0不能作爲被除數",Toast.LENGTH_SHORT).show();
return;
}
d3 = d1 / d2;
}
tempStack.push(d3);
}else{ //爲操作數時候
tempStack.push(c);
}
}
mEditTextShow.setText(""+tempStack.pop());//返回運算結果
newCalc = true;//新一輪計算標誌
}
}
//將中綴表達式轉換爲逆波蘭式,即返回一個後綴隊列
public LinkQueue getSuffixQueue(LinkQueue infixQueue) throws Exception {
LinkQueue suffixQueue = new LinkQueue();
LinkStack tempStack = new LinkStack(); //中間棧,運算時存儲運算符
int length = infixQueue.length();//因爲這隊列是動態的,所以只能用固定的長度值
for(int i = 0;(infixQueue!=null)&&i<length;i++){
String c = (String)infixQueue.poll();//從中綴表達式中出隊第一個
if(!c.equals("")){//如果c不是空格
if(isOperator(c)){//爲運算符
if(!tempStack.isEmpty()){//棧非空,取棧頂優先級高的運算符送往後綴表達式
String ac = (String) tempStack.pop();
while(ac!=null && priority(ac) >= priority(c)){
suffixQueue.offer(ac);
ac = (String) tempStack.pop();
}
if(ac!=null){//若最後一次取出的優先級低的操作符,重新壓棧
tempStack.push(ac);
}
}
tempStack.push(c);
}else{//爲操作數,將其添加到後綴表達式的隊列末尾,裏面有-1
suffixQueue.offer(c);
}
}
}
while(!tempStack.isEmpty()){//棧中剩餘的所有操作符挨個進入後綴表達式
suffixQueue.offer(tempStack.pop());
}
return suffixQueue;
}
//判斷運算法的優先級
public int priority(String c){
if(c.equals("*")||c.equals("/")){
return 2;
}else if(c.equals("-")||c.equals("+")){
return 1;
}else{
return 0;
}
}
//將輸入的字符串式子轉換成隊列,運算符單獨爲一個單元,數字爲一個單元
private LinkQueue getInfixQueue(String value)throws Exception{
//翻轉字符
value = new StringBuilder(value).reverse().toString();
LinkQueue queue = new LinkQueue();
String numberStr="";
while (value.length()>0){
if (isNumber(getLastStr(value))){
numberStr += getLastStr(value);
value = deleteLastStr(value);
}else {
queue.offer(numberStr);
numberStr="";
queue.offer(getLastStr(value));
value = deleteLastStr(value);
}
}
queue.offer(numberStr);
return queue;
}
//判斷輸入的式子是否合法的方法
private boolean isLegal(String value){
if (value.equals("")){ //啥也沒有
Toast.makeText(MainActivity.this,"無計算內容",Toast.LENGTH_SHORT).show();
return false;
}else if (isOperator(getLastStr(value))){ //式子以運算符結尾
Toast.makeText(MainActivity.this,"算式不允以運算符結尾",Toast.LENGTH_SHORT).show();
return false;
}else if (getLastStr(value).equals(".")){
Toast.makeText(MainActivity.this,"算式不允以小數點結尾",Toast.LENGTH_SHORT).show();
return false;
}else {
return true;
}
}
//按到刪除鍵
public void delete(View v){
if (newCalc){//新一輪計算
cleanCalc();
newCalc = false;
}
if (strFormula.length()>0){
strFormula = deleteLastStr(strFormula);
mEditTextShow.setText(strFormula);
if (strFormula.length()==0){//刪除過後爲0,則執行清除操作
cleanCalc();
newCalc = false;
}
}else {
isFirstChar = true;
Toast.makeText(MainActivity.this,"無內容可後退",Toast.LENGTH_SHORT).show();
}
}
//按到清除鍵
public void clean(View v){
cleanCalc();
}
//清除計算
private void cleanCalc(){
mEditTextShow.setText("");
strFormula = ""; //用於記錄算式
isFirstChar = true; //記錄判斷是不是第一個字符
tempNumber = "";//用於記錄一個數字,爲了判斷是否連續輸入小數點
newCalc = true;//用於記錄是否是新的一輪計算
}
//判斷是不是數字
private boolean isNumber(String value){
return "0123456789.".indexOf(value)>-1;
}
//判斷是不是算術符號
private boolean isOperator(String value){
return "+-*/".indexOf(value)>-1;
}
//獲取一個字符串最後一個字符
private String getLastStr(String value){
return value.substring(value.length()-1);
}
//獲取一個字符串除了最後一個字符的其他字符
private String deleteLastStr(String value){
return value.substring(0,value.length()-1);
}
}
風格文件 styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="number">
<item name="android:textSize">30dp</item>
<item name="android:layout_margin">5dp</item>
<item name="android:background">#fff</item>
<item name="android:layout_span">1</item>
</style>
<style name="symbol">
<item name="android:textSize">30dp</item>
<item name="android:layout_margin">5dp</item>
<item name="android:background">#F8E6AC</item>
<item name="android:layout_span">1</item>
</style>
</resources>
顏色文件 colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
<color name="white">#F3F3F3</color>
<color name="blue">#D9F8F8</color>
<color name="red">#F7BCB7</color>
</resources>