华为0904笔试题第二题之极简解释器

2,498 阅读3分钟

今晚虽然没有自己做笔试,但是看到一些笔试完后讨论的题,自己也尝试写了一下,第二题是实现一个极简解释器。

1.题目

题目是实现一个极简解释器,输入会给出代码的行数和每一行代码,每一行代码只存在变量名,等号,数字,加号,空格,不存在其他的符号,并且变量名之间不能有等号。要求输出最后一行的结果。

示例:

输入:

4

xx = 2

yy = 5

zz = xx

cd = xx + yy + zz

输出:9

2.思路

总体思路是定义一个map,将运算看成入map和查询map的过程。

(1)获得每一行输入,然后将每一行输入到getResult函数中处理。

(2)在getResult函数的输入参数是当前行line,当前行数i,总指令行数n

1)首先要以等号为界将表达式分成左右两部分:left和right(需要处理掉多余的空格)

2)然后需要判断右边是单纯的数字或变量还是变量的求和运算:通过计算右边字符串中'+'号的个数plusNum

如果plusNum等于0,则代表右边是单纯的数字或变量:

->如果右边是单纯的数字[每一位都是数字]:将数字的值压入key值为left的map中
->如果右边是变量,需要检查这个变量是否已存在在map中,若存在,则将对应的value值压入key值为left的map中,若不存在,且已是最后一步操作,则输出“NA”

如果plusNum不等于0,则代表右边是求和运算:

-> 需要先获得每个待求和字串,压入堆栈,再依次判断是变量还是数字,进行加和运算,加和的结果入key值为left的map中

3)最后,如果是最后一个操作,则输出对应的值

3.代码

#include <iostream>
#include <vector>
#include <list>
#include <sstream>
#include <map>
#include <stack>
#include <string>
#include <algorithm>
using namespace std;

map<string, int> calulate;

bool isNumber(string str)//用于判断是不是个数字
{
	bool isNum = true;
	for (int i = 0; i < str.size(); i++)
		{
			if (str[i]<'0' || str[i] >'9')
				isNum = false;
		}
	return isNum;
}

void getTheResult(string line, int i, int n)
{
	//将输入行以'='分割成左部分和右部分,并去掉多余的空格
	istringstream input(line);
	string left;
	getline(input,left,'=');
	left.erase(remove(left.begin(), left.end() ,' ' ), left.end());
	string right;
	getline(input, right);
	right.erase(remove(right.begin(), right.end(), ' '), right.end());
	//判断右侧是否有求和运算
	int plusNum = 0;
	for (int i = 0; i < right.size(); i++)
	{
		if (right[i] == '+')
			plusNum++;
	}
	//如果右边是单个数字或变量,入map
	bool isNum = isNumber(right);
	if (plusNum == 0)
	{
		if (isNum == true)//如果是数字
			calulate[left] = stoi(right);
		else//如果是变量
		{
			if ((calulate.find(right) == calulate.end()) && (i == n))
				cout << "NA" << endl;
			if (calulate.find(right) != calulate.end())
				calulate[left] = calulate[right];
		}
	}
	else //如果右边是公式
	{
		//将待求和部分入栈
		istringstream rightTmp(right);
		stack <string> num;
		int i = plusNum;
		string tmp;
		while (i--)
		{
			getline(rightTmp, tmp, '+');
			num.push(tmp);
		}
		getline(rightTmp, tmp);
		num.push(tmp);
		//根据每部分是数字还是变量求和
		i= plusNum+1;
		int res = 0;
		while (i--)
		{
			string tmp = num.top();
			if (isNumber(tmp))
				res += stoi(tmp);
			else if(calulate.find(right) == calulate.end())
				res += calulate[tmp];
			else
			{
				if(i==n)
					cout << "NA" << endl;
			}	
			num.pop();
		}
		calulate[left] = res;
	}
	if (i == n)//如果是最后一次操作,输出
	{
		cout<< calulate[left] <<endl;
	}
}

int main()
{
	int n;
	cin >> n;
	string space;
	getline(cin,space);
	int i = 0;
	while (i++<n)
	{
		string line;
		getline(cin,line);
		getTheResult(line,i,n);
	}
}

4.小结

<1>以=分割出str的左部分和右部分:

isstringstream input(str);
string left;
getline(input,left,'=');//left里是等号左边的内容,input里剩下等号右边的内容
string right;
getline(input,right);

<2>去除string str中空格的现有方法:需要包含头文件algorithm

str.erase(remove(str.begin(),str.end(),' '),str.end());

<3>字符串数字转换

string a = to_string(3.1415);//数字转字符
int a = stoi("123");//字符转数字

代码只经过了简单的样例测试,没有线上跑过,如有不足可以提出!