K:雙棧法求算術表達式的值

相關介紹:

 該算法用於求得一個字符串形式的表達式的結果。例如,計算1+1+(3-1)*3-(21-20)/2所得的表達式的值,該算法利用了兩個棧來計算表達式的值,爲此,稱爲雙棧法,其實現簡單且易於理解。但其要求將咱們平時所看到的表達式的模式轉化爲徹底加括號的形式。如表達式,1+1+(3-1)*3-(21-20)/2是咱們平時習慣上的樣子,其徹底加括號的形式爲,(((1+1)+((3+1)*2))-((21-20)/2))。由此可知,計算一個字符串形式的表達式有兩個任務,第一是將輸入的算術表達式轉化爲一個徹底加括號的算術表達式,第二是將一個徹底加括號的算術表達式進行運算,求得運算的結果。爲方便起見,這裏只考慮加減乘除(+、-、×、÷)這四個基本運算html

將算術表達式轉化爲徹底加括號:

其基本思想以下:java

  1. 初始化一個運算符棧和一個操做數棧
  2. 從算術表達式輸入的字符串中從左到右的讀取一個字符
  3. 若當前字符爲操做數,則直接將該操做數壓入操做數棧中
  4. 若當前字符是左括號"("時,將其壓入運算符棧中
  5. 若當前字符爲運算符時,則:
    1. 當運算符棧爲空的時候,則將其壓入運算符棧中
    2. 當此運算符的優先級高於棧頂元素的運算符的時候,則將此運算符壓入操做數棧中,不然,彈出運算符棧頂元素和操做數棧頂的兩個元素,爲其添加上相應的運算符以及左括號和右括號以後,將其壓入操做數棧中,將其當作一個總體
  6. 若當前字符爲右括號")"時,反覆將棧頂元素彈出,每次彈出一個運算符的時候,從操做數棧中彈出棧頂的兩個元素爲其添加上相應的運算符以及左右括號以後,再將其壓入操做數棧中,將其當作一個總體。直至運算符棧的棧頂元素爲左括號爲止,再將左括號出棧並丟棄。
  7. 若讀取還未完畢,重複步驟2
  8. 若讀取完畢,則將棧中剩餘的全部運算符依次彈出,每次彈出一個運算符時,同時彈出操做數棧的兩個元素,併爲其添加上相應的運算符以及左右括號以後,將其做爲一個總體,壓入操做數棧中。直到運算符棧爲空爲止,則操做數棧中的結果,即爲所得的結果。

運算符的優先級以下表所示:正則表達式

運算符 +(加)、-(減) *(乘)、/(除)
優先級 1 2
其中,其數值越大的表示其運算符的優先級越高。

示例代碼以下:算法

package queueandstack;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
/**
 * 該類用於演示使用雙棧法求解算術表達式的結果
 * @author 學徒
 *
 */
public class DoubleStackGetResult
{
	
	public static void main(String[] args)
	{
		DoubleStackGetResult ds=new DoubleStackGetResult();
		System.out.println(ds.ComplementBrackets("1+1+(3+1)*2-(21-20)/2"));
	}
	//該方法用於實現一個符號表
	private static Map<String,Integer> getMap()
	{
		Map<String,Integer> temp=new HashMap<String,Integer>();
		//定義各個運算符的優先級,其中,x和÷字符用於兼容
		temp.put("*", 2);
		temp.put("/", 2);
		temp.put("×",2);
		temp.put("÷",2);
		temp.put("+", 1);
		temp.put("-",1);
		return temp;
	}
/**
 * 該方法用於將輸入的,習慣上的算術表達式轉化爲徹底加括號的形式
 * @param input 輸入的習慣上的算術表達式
 */
	//該符號表用於定義運算符的優先級
	private Map<String,Integer> table=getMap();
	//該字符串爲用於匹配數字的
	private String rexNumber="\\d+";
	private String rexOperator="[((+\\-*/×÷))]";
	//操做數棧
	Stack<String> number=new Stack<String>();
	//運算符棧
	Stack<String> save=new Stack<String>();
	/**
	 * 該方法用於將中序表達式轉化爲後序表達式,並對其轉化後的表達式以字符串的形式進行返回
	 * @return 後序表達式
	 */
	public String ComplementBrackets(String input)
	{
		//用於得到字符串中的數字所組成的數組
		String[] numbers=input.split(rexOperator);
		//用於指示是獲取了第幾個數字數組中的數字總體
		int order=0;
		//用於指示當前字符的指針
		int i=0;
		while(i<input.length())
		{
			//得到當前字符
			String thisString=String.valueOf(input.charAt(i));
			//當前該字符爲運算符或者括號時,即當前該字符不爲數字時
			if(thisString.matches(rexOperator))
			{
				//噹噹前字符不爲左括號或者右括號時(即爲運算符)
				if(!thisString.matches("[()()]"))
				{
					//用於記錄棧頂元素的優先級
					int temporary=0;
					//獲取當前字符的優先級
					int present=table.get(thisString);
					//當操做數的棧不爲空的時候
					if(!save.isEmpty())
					{
						//查看棧頂元素的字符以及其優先級
						String top=save.peek();
						if(!top.matches("[((]"))
						{
							temporary=table.get(top);
						}
					}
					//當棧頂元素的操做符的優先級比當前操做符的優先級還要高或者相同時,對其進行彈出操做,直到棧頂元素的優先級比當前操做符的優先級要低
					if(temporary>=present)
					{
						while(!save.isEmpty()&&table.get(save.peek())>=present)
						{
							String number1=number.pop();
							String number2=number.pop();
							number.push("("+number2+save.pop()+number1+")");
						}
					}
					save.push(thisString);
				}
				//噹噹前的字符爲左括號的時候,直接將其壓入棧中
				else if(thisString.matches("[((]"))
				{
					save.push(thisString);
				}
				//噹噹前的字符爲右括號的時候,將其棧中的元素一直彈出,直至遇到左括號結束,並將左括號彈出
				else
				{
					while(!save.peek().matches("[((]"))
					{
						String number1=number.pop();
						String number2=number.pop();
						number.push("("+number2+save.pop()+number1+")");
					}
					//彈出其左括號
					save.pop();
					/*String number1=number.pop();
					String number2=number.pop(); 
					number.push("("+number2+save.pop()+number1+")");*/
				}
				i++;
			}
			//當前該字符爲數字的時候
			if(thisString.matches(rexNumber))
			{
				//用於存儲數字數組中的數字字符串
				String numberString=null;
				do
				{
					numberString=numbers[order];
					//當數字字符串中的數字不爲空時(因爲可能會是空字符串的出現),將整個中序表達式的字符串的指針進行向右移動
					if(!numberString.trim().equals(""))
					{
						i+=numberString.length();
						order++;
						break;
					}
					else
					{
						order++;
					}
				}while(true);
				//將數字直接壓入操做數棧中
				number.push(numberString);
			}
		}
		//將棧中剩餘的字符進行彈出
		while(!save.isEmpty())
		{
			String number1=number.pop();
			String number2=number.pop();
			number.push("("+number2+save.pop()+number1+")");
		}
		return number.pop();
	}
}



運行結果以下:
(((1+1)+((3+1)*2))-((21-20)/2))

計算徹底加括號表達式的結果:

其基本思想以下:數組

  1. 初始化兩個棧,一個用於保存運算符,一個用於保存操做數
  2. 從左往右依次遍歷字符串表達式的每一個字符
  3. 將操做數壓入操做數棧中
  4. 將運算符壓入運算符棧中
  5. 忽略左括號
  6. 在遇到右括號時,彈出一個運算符以及所需數量的操做數,並將運算符和操做數的運行結果壓入到操做數棧中
  7. 處理完最後一個右括號,操做數棧上只會有一個值,它就是表達式的值

這種方法不難理解,每當算法遇到一個被括號包圍並由一個運算符和兩個操做數組成的子表達式時,它都可以將運算符和操做數的計算結果壓入操做數棧中,這樣的結果就是在輸入中用這個運算所得的值代替了該子表達式,所以,用這個值代替子表達式獲得的結果和原表達式相同,經過反覆運用以上的規律,最終能夠獲得該表達式的解。this

其示例代碼以下:spa

/**
 * 
 * 用於計算一個徹底加括號的算術表達式的結果
 * @param inputStr 其參數爲徹底加括號的算術表達式
 *
 */
public double getResult(String inputStr)
{
	//用於將輸入的字符串分割成數字的正則表達式
	String regex="[((+\\-*/×÷))]";
	//用於獲取獲得數字
	String[] numbers =inputStr.split(regex);
	int order=0;
	//兩個棧,一個爲操做數棧,一個爲運算符棧
	Stack<String> ops=new Stack<String>();
	Stack<Double> vals=new Stack<Double>();
	char[] input=inputStr.toCharArray();
	//用於遍歷的字符的指針
	int index=0;
	while(index<input.length)
	{
		//讀取對應的字符
		char ch=input[index];
		//忽略左括號
		if(ch=='('||ch=='(');
		else if(ch=='+')
			ops.push(String.valueOf(ch));
		else if(ch=='-'||ch=='-')
			ops.push(String.valueOf(ch));
		else if(ch=='*'||ch=='×')
			ops.push(String.valueOf(ch));
		else if(ch=='/'||ch=='÷')
			ops.push(String.valueOf(ch));
		else if(ch==')'||ch==')')
		{
			//當爲右括號的時候,彈出運算符以及操做數,計算結果並壓入棧中
			String op=ops.pop();
			double v=vals.pop();
			if(op.equals("+"))
				v=vals.pop()+v;
			else if(op.equals("-")||op.equals("-"))
				v=vals.pop()-v;
			else if(op.equals("*")||op.equals("×"))
				v=vals.pop()*v;
			else if(op.equals("/")||op.equals("÷"))
				v=vals.pop()/v;
			vals.push(v);
		}
		else
		{
			//用於存儲數字數組中的數字字符串
			String numberString=null;
			do
			{
				numberString=numbers[order];
				//當數字字符串中的數字不爲空時(因爲可能會是空字符串的出現),將整個中序表達式的字符串的指針進行向右移動
				if(!numberString.trim().equals(""))
				{
					index+=numberString.length()-1;
					order++;
					break;
				}
				else
				{
					order++;
				}
			}while(true);
			vals.push(Double.parseDouble(numberString));
		}
		++index;
	}
	return vals.pop();
}

回到目錄|·(工)·)指針

相關文章
相關標籤/搜索