近日學習了android的基本界面和調用,試試寫一個科學計算器。雖然還沒找到工作,可是貌似工作可遇而不可求啊! 開心就好...
需求:
1.計算器顯示輸入的表達式
2.支持()運算符
3.支持多次方、三角函數(cos,tan,sin)
4.支持10位π、e
5.支持快速開方
6.支持邏輯運算
7.運算精度和範圍(10^-8 - 10^8)
8.支持all_clear快速清理表達式閱覽框和結果框,支持del刪除表達式最後一個字符
分析:
該計算器的重點不在於如何計算,在於如何把表達式導入計算機交給系統計算。如:輸入表達式1+1*2 ,需要對表達式進行分析和求解。
設計解決方案:
1.使用二叉樹的形式用結點存儲值 ,按優先級進行中序排序 ,根結點即爲最終結果
2.直接使用數組的形式,對下標進行計算
最終解決方案:
界面設計:
-------算法一 直接使用數組實現(不完整)--------------------------------------------------------------------------------------------------------------------------------------------------------
//分析表達式
/*
* 以+、-、*、/爲分割符號 將所有數字取出來 存入數組
* 將所有符號取出來 存入數組
* 遍歷符號數組,設置優先級 *、/優先級爲1; +,-優先級爲0
*
* 按優先級和數組下標爲次序進行計算
*/
private double calculate(StringBuffer expressionStr){
double result=0;
List symbol = new ArrayList();
List<StringBuffer> nums = new ArrayList();
char temp;
boolean flag=false;//判斷連續數字
for(int i=0,index_nums=-1;i<expressionStr.length();i++){
temp=expressionStr.charAt(i);
if('+'==temp||'-'==temp||'X'==temp||'/'==temp){
symbol.add(temp);
flag=false;
}else{//('0'==temp||'1'==temp||'2'==temp||'3'==temp||'4'==temp||'5'==temp||'6'==temp||'7'==temp||'8'==temp||'9'==temp||'.'==temp){
if(flag==true){
nums.get(index_nums).append(temp);
}else {
index_nums++;
nums.add(new StringBuffer(temp+""));
}
flag=true;
}
}
//將組合的數字字符串每一個轉型爲double型
List<Double> nums_dou=new ArrayList();
for(int i=0;i<nums.size();i++){
nums_dou.add(Double.valueOf(nums.get(i).toString()));
}
//開始計算
//計算方法,採用數組的形式
List<Double> results = new ArrayList();
for(int i=0;i<symbol.size();i++){
results.add(0d);
}
for(int i=0;i<symbol.size();i++){
if(i==0){
if(symbol.get(i).toString().equals("X")){
results.set(i, nums_dou.get(i)*nums_dou.get(i+1));
}
if(symbol.get(i).toString().equals("/")){
results.set(i, nums_dou.get(i)/nums_dou.get(i+1));
}
if(symbol.get(i).toString().equals("+")){
results.set(i, Double.valueOf((nums_dou.get(i)+nums_dou.get(i+1))));
}
if(symbol.get(i).toString().equals("-")){
results.set(i, nums_dou.get(i)-nums_dou.get(i+1));
}
}else
if(symbol.get(i).toString().equals("X")||symbol.get(i).toString().equals("/")){
if(results.get(i-1)==0){
if(symbol.get(i).toString().equals("X")){
results.set(i, nums_dou.get(i)*nums_dou.get(i+1));
}else{
results.set(i, nums_dou.get(i)/nums_dou.get(i+1));
}
}else {
if(symbol.get(i).toString().equals("X")){
results.set(i, results.get(i-1)*nums_dou.get(i+1));
}else{
results.set(i, results.get(i-1)/nums_dou.get(i+1));
}
}
}else {
if(results.get(i-1)==0){
if(symbol.get(i).toString().equals("+")){
results.set(i, nums_dou.get(i)+nums_dou.get(i+1));
}else{
results.set(i, nums_dou.get(i)-nums_dou.get(i+1));
}
}else {
if(symbol.get(i).toString().equals("+")){
results.set(i, results.get(i-1)+nums_dou.get(i+1));
}else{
results.set(i, results.get(i-1)-nums_dou.get(i+1));
}
}
}
System.out.println("results.get(i)->>"+results.get(i));
result=results.get(i);
}
System.out.println("Result->>"+result);
return result;
}
--------------------------我想還是用棧或者二叉樹比較好實現點----------
因爲java中沒有棧這種數據結構,那麼只能模擬了。這裏我使用數組來模擬棧
package tk.orangers.calculate;
//利用數組實現簡單的堆棧
public class arrayStact {
private int pointcounter;// 棧指針
double[] stact = new double[100];
public arrayStact() {
for (int i = 0; i < stact.length; i++)
stact[i] = -1;
pointcounter = 0;
}
public void push(double temp) {
pointcounter++;
if (pointcounter < 100) {
for (int i = pointcounter; i > 0; i--)
stact[i] = stact[i - 1];
stact[0] = temp;
} else
System.out
.println("Error:表達式長度超過了棧大小~!\n");
}
public double pop() {
double temptop = -1;
if (isEmpty()) {
System.out.println("Error:棧是空的!\n");
} else {
temptop = stact[0];
for (int i = 0; i < pointcounter; i++)
stact[i] = stact[i + 1];
pointcounter--;
}
return temptop;
}
public double gettop() {
return stact[0];
}
private boolean isEmpty() {
if (pointcounter == 0)
return true;
else
return false;
}
}
分析字符串表達式,將字符串中的數字與符號分割開來
之後分別使用兩個棧來存放運算符號和運算者
關於優先級,借鑑了數據結構中的驗證矩陣來求解
根據符號優先級,依據符號棧進行計算
package tk.orangers.calculate;
public class stringAnalysis{
arrayStact stact_nums = new arrayStact();// 存放操作數
arrayStact stact_symbol = new arrayStact();// 存放運算符號
String[] unit = new String[200]; // 存放解析出來的操作數與運算符
int[][] priority = { // + - * / ( ) 優先級比較矩陣
{ 2, 2, 1, 1, 1, 2, 2 },
{ 2, 2, 1, 1, 1, 2, 2 },
{ 2, 2, 2, 2, 1, 2, 2 },
{ 2, 2, 2, 2, 1, 2, 2 },
{ 1, 1, 1, 1, 1, 0, 3 },
{ 2, 2, 2, 2, 3, 2, 2 },
{ 1, 1, 1, 1, 1, 3, 0 },
};
// 0表示相等 1表示小於 2表示大於 3表示錯誤
// + 用0表示,- 用1表示,* 用2表示,/ 用3表示,
// ( 用4表示,) 用5表示,# 用6表示
//橫與縱的關係 如:第一行第三列爲1 表示+的優先級小於*
private String temp;// 用於構造函數
private int arraypoint = 0;// 記錄unit數組的存儲長度
private int i = 0;// 讀取unit數組的元素
private String tempstring;// 保存臨時unit的值
private int start = 0; // 數字字符串開始位置
private int counter = 0; // 字符個數計數
private int target = 0; // 保存開始計數位置
private int lab = 1; // 表示計數結束輸出數串
private int index = 0; // 表示字符串讀取位置的計數
private int iscorrect = 1;// 表示是否繼續讀取整個字符串到存放數組(表示是是否是正確地表達式),1表示繼續,0表示停止
private int isrecord = 0;// 表示是否存入數組,1表示存入數組合,0表示不存入數組
private int isnext = 1; // 表示檢測每一個數組單元值,如果非法爲0,不非法爲1(即進行下一步)
private int leftbracket = 0, rightbracket = 0;// 左,右括號記數目
private double result=0d;//結果
public double getResult( ){//計
return this.result;
}
public stringAnalysis(String passtemp) {
this.temp = passtemp;
processwhitespace();
processexpression();
if (leftbracket != rightbracket) {
isnext = 0;
System.out
.println("Erro:括號不對稱哦~~!");
}
if (isnext == 1)
computeexpression();
}
private void processwhitespace() {//將表達式剔除空格
String emptystring = "";
String[] tempstring = temp.split(" ");
for (int i = 0; i < tempstring.length; i++) {
emptystring += tempstring[i];
}
System.out.println("Log:被計算的表達式是:\n" + emptystring);
System.out.println("\n");
temp = emptystring + "#";
stact_symbol.push(6);// 初始化操作符堆棧
}
private void partprocessexpression(String tempstringtemp) {
if (iserrorexpression(tempstringtemp))
isnext = 0;
else {
if (tempstringtemp == "-" && index == 0)
isrecord = 1;
else if (temp.charAt(index - 1) == ')') {
unit[arraypoint] = tempstringtemp;
arraypoint++;
} else {
lab = 1;
if (lab == 1) {
target = 0;
lab = 0;
if (counter == 0)
;// ()時候移位
else {
if (isrecord == 1) {
unit[arraypoint] = "-"
+ temp.substring(start, start + counter);// 開始第一位爲負數
arraypoint++;
isrecord = 0;
} else {
unit[arraypoint] = ""
+ temp.substring(start, start + counter);
arraypoint++;
}
}
counter = 0;
}
unit[arraypoint] = tempstringtemp;
arraypoint++;
}// end inner else
}// end outer else
}
private void processexpression()// 讀取表達式,將預算符號與操作數分開,並存入數組
{
for (; index < temp.length(); index++) {
switch (temp.charAt(index)) {
case '(':
if (iserrorexpression("("))
isnext = 0;
else {
leftbracket++;
unit[arraypoint] = "(";
arraypoint++;
if (temp.charAt(index + 1) == '-'&& temp.charAt(index + 2) - '0' >= 1&& temp.charAt(index + 2) - '0' <= 9) {
int end = 0;
for (int tempm = index + 1; tempm < temp.length(); tempm++) {
if (temp.charAt(tempm) == ')') {
end = tempm;
break;
}
}
unit[arraypoint] = temp.substring(index + 1, end);
arraypoint++;
index = end - 1;
target = 0;
lab = 0;
counter = 0;
}
}// end else
break;
case ')':
if (index == 0)
isnext = 0;
else {
partprocessexpression(")");
rightbracket++;
}
break;
case '+':
if (index == 0)
isnext = 0;
else
partprocessexpression("+");
break;
case '-':
partprocessexpression("-");
break;
case '*':
if (index == 0)
isnext = 0;
else
partprocessexpression("*");
break;
case '/':
if (index == 0)
isnext = 0;
else
partprocessexpression("/");
break;
case '#':
unit[arraypoint] = "#";
break;
default:
if (target == 0) {
start = index;
lab = 0;
target = 1;
}
if (lab == 0)
counter++;
if (start + counter == temp.length() - 1) {
unit[arraypoint] = ""+ temp.substring(start, start + counter);
arraypoint++;
}
}// end switch
}// edn for
}// end processexpression
private boolean iserrorexpression(String errortempstring) {//檢查表達式錯誤
boolean iserror = false;
switch (errortempstring.charAt(0)) {
case '(':
if (temp.charAt(index - 1) == ')'
|| temp.charAt(index + 1) == ')'
|| (temp.charAt(index - 1) >= '0' && temp.charAt(index - 1) <= '9'))
iserror = true;
break;
case ')':
if (temp.charAt(index - 1) == '('
|| temp.charAt(index + 1) == '('
|| (temp.charAt(index + 1) >= '0' && temp.charAt(index + 1) <= '9'))
iserror = true;
break;
case '+':
case '*':
case '/':
if (temp.charAt(index - 1) == '(' || temp.charAt(index - 1) == '+'
|| temp.charAt(index - 1) == '-'
|| temp.charAt(index - 1) == '*'
|| temp.charAt(index - 1) == '/'
|| temp.charAt(index + 1) == ')'
|| temp.charAt(index + 1) == '+'
|| temp.charAt(index + 1) == '-'
|| temp.charAt(index + 1) == '*'
|| temp.charAt(index + 1) == '/')//符號重複性檢查
iserror = true;
break;
case '-':
if (index != 0) {
if (temp.charAt(index - 1) == '+'
|| temp.charAt(index - 1) == '-'
|| temp.charAt(index - 1) == '*'
|| temp.charAt(index - 1) == '/'
|| temp.charAt(index + 1) == ')'
|| temp.charAt(index + 1) == '+'
|| temp.charAt(index + 1) == '-'
|| temp.charAt(index + 1) == '*'
|| temp.charAt(index + 1) == '/'){//針對-號的處理 考慮負數情況
iserror = true;
}
if (temp.charAt(index - 1) == '(') {
if (temp.charAt(index + 1) - '0' >= 1
&& temp.charAt(index + 1) - '0' <= 9)
iserror = false;
else
iserror = true;
}
} else {
if (temp.charAt(index + 1) == ')'
|| temp.charAt(index + 1) == '+'
|| temp.charAt(index + 1) == '-'
|| temp.charAt(index + 1) == '*'
|| temp.charAt(index + 1) == '/')
iserror = true;
}
break;
default:
System.out.println("Error6 at" + (index - 1) + "~~" + (index + 1));
}// end switch
return iserror;
}
private void computeexpression() {//計算
tempstring = unit[i];
while (tempstring != "#" || stact_symbol.gettop() != 6) {//遍歷unit
if (tempstring != "+" && tempstring != "-" && tempstring != "*"&& tempstring != "/" && tempstring != "("&& tempstring != ")" && tempstring != "#") {
stact_nums.push(Double.parseDouble(unit[i]));//數字入棧
tempstring = unit[++i];
} else {
switch (tempstring.charAt(0)) {//符號入棧 並根據符號優先級進行計算
case '+':
compareandprocess(0);
break;
case '-':
compareandprocess(1);
break;
case '*':
compareandprocess(2);
break;
case '/':
compareandprocess(3);
break;
case '(':
compareandprocess(4);
break;
case ')':
compareandprocess(5);
break;
case '#':
compareandprocess(6);
break;
}// end switch
} // end else
}// end while
}
private void compareandprocess(int a) {
switch (priority[(int)stact_symbol.gettop()][a]) {//優先級驗證
case 0: //優先級相等
stact_symbol.pop();
tempstring = unit[++i];
break;
case 1://優先級小於
stact_symbol.push(a);
tempstring = unit[++i];
break;
case 2://優先級大於當前棧頂符號 則計算
partcompareandprocess();
break;
case 3: {//錯誤 不可比較的錯誤
System.out.println("error~!");
System.out.println(stact_symbol.gettop() + " " + a);
}
}
}
private void partcompareandprocess() {
double tempa, tempb, tempc;
int tempoperator;
tempoperator = (int)stact_symbol.pop();
tempb = stact_nums.pop();
tempa = stact_nums.pop();
switch (tempoperator) {
case 0:
tempc = tempa + tempb;
stact_nums.push(tempc);
result=tempc;
break;
case 1:
tempc = tempa - tempb;
stact_nums.push(tempc);
result=tempc;
break;
case 2:
tempc = tempa * tempb;
stact_nums.push(tempc);
result=tempc;
break;
case 3:
tempc = tempa / tempb;
stact_nums.push(tempc);
result=tempc;
break;
}
}
}
待續...