1. 程式人生 > >第四章棧(2)

第四章棧(2)

2. 一個算術表示式的字尾表示式形式如下:
op1 op2 operator
使用兩個棧,一個用來儲存運算元,另外一個用來儲存操作符,設計並實現一個JavaScript函式,
該函式可以將中綴表示式轉換為字尾表示式,然後利用棧對該表示式求值。
    考慮優先順序:
        1.先乘除
        2.後加減
        3.有括號先算括號裡
    

    基本思路:為了完成算術表示式的計算,用到了兩個棧,一個用於存放運算元,另一個用於存放操作符。

    假設:程式中定義了兩個棧:numStack(用來存放運算元)、operatorStack(用於存放操作符)。
    在處理運算元和操作符之前,首先將它們壓入棧中。當要處理一個操作符時,從operatorStack中將它彈出,
    然後將它應用在來自numStack的前兩個運算元上,得到的結果再壓入numStack中。

實現的詳細步驟:

    1.掃描階段:程式從左到右掃描表示式,提取運算元、運算子和括號。
        1)如果提取的字元是一個運算元,將它壓入numStack中。
        2)如果提取的字元是一個+或-的運算子,因為+、-運算子在算術表示式中的優先順序是最低的,所以此時在將+或者-運算子插入棧中之前,可以處理operatorStack棧頂的所有運算子,最後將提取出來的運算子壓入operatorStack中。
        3)如果提取的字元是一個*或/的運算子,則處理operatorStack棧頂的所有*和/的運算子,最後將新提取出來的運算子壓入operatorStack中。
        4)如果提取出來的運算子是一個"(",則將它壓入operatorStack中。
        5)如果提取出來的運算子是一個")",則重複處理operatorStack棧頂的運算子,直到看到棧頂的運算子為")"。

    2.清除棧階段:重複處理來自operatorStack棧頂的運算子,直到operatorStack為空為止。

function operatorCge(numStack,operatorStack)
{	
	let op1,op2,operator;
	op1=numStack.pop(); //取運算元的棧頂元素
	op2=numStack.pop(); //取運算元的棧頂元素
	operator=operatorStack.pop();//取操作符的棧頂元素
	switch(operator)
	{  
		case "+":
		  numStack.push(parseFloat(op2)+parseFloat(op1)); //將字串轉換成數字
		  break;
		case "-":
		  numStack.push(op2-op1);
		  break;
		case "*":
		  numStack.push(op2*op1);
		  break;
		case "/":
		  numStack.push(op2/op1);
		  break;		  		  
	}
}

function evaluateExpression(str){

let numStack=new Stack(); //存放運算元
let operatorStack=new Stack();//存放運算子

str=str.split("");

for(let i=0;i<str.length;i++)
{
	if(str[i].trim()=="") //如果字串為空,則跳過此次迴圈
	{
		continue;
	}else if(str[i].trim()=="+"||str[i].trim()=="-")
	{		
		//如果字串為“+”或“-”,則執行棧中已存資料的加減乘除
		while(!operatorStack.isEmpty() && 
			(   operatorStack.peek() == "+" || 
				operatorStack.peek() == "-" || 
				operatorStack.peek() == "*" ||
				operatorStack.peek() == "/"
			)){
                   
                operatorCge(numStack,operatorStack);
 
              }
              operatorStack.push(str[i]);
	}else if(str[i].trim()=="*"||str[i].trim()=="/")
	{	
	    //如果字串為“+”或“-”,則執行棧中已存資料的乘除計算
		while(!operatorStack.isEmpty() && 
			  (operatorStack.peek() == "*" ||
			   operatorStack.peek() == "/"
			  )){
                  operatorCge(numStack,operatorStack);
              	  console.log("*:",numStack.peek());
              }
              operatorStack.push(str[i]);
	}else if(str[i].trim()=="(")
	{	//如果遇到左括號,則將左括號壓入操作符棧中
		operatorStack.push(str[i]);
	}else if(str[i].trim()==")")
	{	//如果遇到右括號,則計算棧中的資料,直到遇到左括號為止
		while(operatorStack.peek()!="(")
		{	
			operatorCge(numStack,operatorStack);
		}
		operatorStack.pop();//將進行過計算的左括號彈出
	}else
	{	//如果遇到的是運算元,則將運算元直接壓入運算元棧中
		numStack.push(str[i]);
	}

}

//對棧中資料進行計算,知道棧為空為止
while(!operatorStack.isEmpty())
{	
	operatorCge(numStack,operatorStack);
}

  return numStack.pop();

}

let str="4+5-3*9-(2+ 3 )";
let result=evaluateExpression(str);
console.log(result);//-23