1. 程式人生 > >遞迴_表示式求值_CH1802_表示式計算

遞迴_表示式求值_CH1802_表示式計算

思路分析: 

    此處不使用棧求表示式值的演算法, 而使用遞迴演算法, 注意題目中指出表示式中可能存在多餘括號, 因此應首先去除多餘括號得到等價的合法表示式(使用棧進行配對即可), 接下來將表示式長度視為問題的規模, 為減小問題的規模實現遞迴, 根據運算子優先順序特點, 如果表示式中存在不在任何括號中的加減號, 那麼將最後一個不在任何括號中的加減號作為表示式分割點, 如果存在表示式中存在不在任何括號中的乘除號, 那麼將最後一個不在任何括號中的乘除號作為表示式分割點, 否則以最後一個不在任何括號中的乘方號作為表示式的分割點, 下面給出基於此思想AC程式碼(實際上, 可通過對錶達式長度進行數學歸納, 證明下述程式能正確計算表示式的值, 具體證明過程此處不再贅述)

//CH1802_表示式計算
#include <cstdio>
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int MAX = 35, NIL = 0x3f3f3f3f;
char cstr[MAX];
list<char> li;
vector<list<char>::iterator> ve; vector<int> vee;
int getRes(int l, int r){	                             	
	int x = NIL, y = NIL, z = NIL;//x:cstr中最後一個不在括號中的加減號下標,y:乘除號,z:乘方號
	for(int i = l; i <= r; ++i)
		if(cstr[i] == '(') vee.push_back(i);
		else 
			if(cstr[i] == ')') vee.pop_back();
			else
				if((cstr[i] == '+' || cstr[i] == '-') && vee.empty()) x = i;
				else if((cstr[i] == '*' || cstr[i] == '/') && vee.empty()) y = i;
				else if(cstr[i] == '^' && vee.empty()) z = i;
	if(x == NIL && y == NIL && z == NIL){
		if(cstr[l] == '(') return getRes(l + 1, r - 1);
		int res = 0; for(int i = l; i <= r; ++i) res = res * 10 + cstr[i] - '0';
		return res;
	}
	if(x != NIL)
		if(cstr[l] == '-') return -getRes(l + 1, r);
		else return cstr[x] == '+'? getRes(l, x - 1) + getRes(x + 1, r)
								  : getRes(l, x - 1) - getRes(x + 1, r);
	if(y != NIL)
 		return cstr[y] == '*'? getRes(l, y - 1) * getRes(y + 1, r)
		 					 : getRes(l, y - 1) / getRes(y + 1, r);
 	return pow((double)getRes(l, z - 1), getRes(z + 1, r));	
}
int main(){
	int len = (scanf("%s", cstr + 1), strlen(cstr + 1));
	for(int i = 1; i <= len; ++i) li.push_back(cstr[i]);
	for(list<char>::iterator it = li.begin(); it != li.end(); ++it)
		if(*it == '(') ve.push_back(it);
		else if(*it == ')' && !ve.empty()) ve.pop_back();
	for(int i = 0; i < ve.size(); ++i) li.erase(ve[i]);
	copy(li.begin(), li.end(), cstr + 1); len = li.size();
	cout << getRes(1, len) << endl;
	return 0;
}