码迷,mamicode.com
首页 > 其他好文 > 详细

一次计算器的练习

时间:2015-02-27 12:05:21      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:

我的个人博客( 肥龙的博客)发表了新文章了!
欢迎大家过来阅读,以下是文章的连接地址

http://www.comingcode.com/?p=289


    最近没有什么事情做,空余时间就在看看书,每次都能打开编译原理来看,但是都是看不了多少就开始犯困了。无聊之际,想到自己连计算器都没有实现过,这个可以动手做做。计算器最主要的还是如何将一个算式计算出来结果,而我想到估计也跟编译原理说的有点相似吧,然后就开始动手了,下面就是两个实现版本:

    版本一:使用vector装载算符和数字,然后通过递归来处理小括号优先级问题

int Expr(string vStr)
{
	//识别算符与数字
	char* tPos = (char*)vStr.c_str();
	vector<string> tItemList;
	while((tPos-vStr.c_str()) < vStr.size())
	{
		while(*tPos == ‘ ‘)
			tPos++;

		if(*tPos == ‘(‘ || *tPos == ‘)‘ || *tPos == ‘+‘ || *tPos == ‘-‘ || *tPos == ‘*‘ || *tPos == ‘/‘)
		{
			string tTemp = " ";
			tTemp[0] = *tPos;
			tItemList.push_back(tTemp);

			tPos++;
		}
		else if(*tPos>=‘0‘&&*tPos<=‘9‘)
		{
			char* tTempPos = tPos;
			while(*tPos>=‘0‘&&*tPos<=‘9‘)
				tPos++; 

			tItemList.push_back(vStr.substr(tTempPos-vStr.c_str(), tPos-tTempPos));
		}
		else
			tPos++;
	}

	//识别括号,采用递归的方式处理小括号高优先级问题
	int i = 0;
	while(i < tItemList.size())
	{
		int tLeftCount = 0;
		int tLeftIndex = 0;
		for(; i<tItemList.size(); i++)
		{
			if(tItemList[i] != "(" && tItemList[i] != ")")
				continue;

			if(tItemList[i] == "(")
			{
				tLeftCount++;
				if(1 == tLeftCount)
					tLeftIndex = i;
			}
			else
			{
				tLeftCount--;
				if(tLeftCount == 0)
				{
					string tSubStr = "";
					for(int j=tLeftIndex+1; j<i;j++)
						tSubStr = tSubStr+tItemList[j];

					//递归子算式
					int retNum = Expr(tSubStr);

					//由于递归返回的结果只有一个,原来算式比返回的结果长,因此只留了一个位置用来保存结果,子算式的其他位置都置空
					for(int j=tLeftIndex; j<i; j++)
						tItemList[j] = "";

					//为了简单处理,将子算式返回的结果存放在右括号的位置
					char tTempArray[32] = {0};
					itoa(retNum, tTempArray, 10);
					tItemList[i] = string(tTempArray);
				}
			}
		}
	}

	//将上面置为空的元素从vector中删除
	for(vector<string>::iterator tIter=tItemList.begin(); tIter!=tItemList.end(); )
	{
		if(*tIter == "")
			tIter = tItemList.erase(tIter);
		else
			tIter++;
	}

	//到这里位置,算式中已经没有任何括号了
	//由于乘除优先级高,这里先处理乘除法
	for(int i=0; i<tItemList.size(); i++)
	{
		if(tItemList[i] != "*" && tItemList[i] != "/")
			continue;

		int tLeftNum = 0;
		if(i > 0)
			tLeftNum = atoi(tItemList[i-1].c_str());

		int tRightNum = 0;
		if(i < (tItemList.size()-1))
			tRightNum = atoi(tItemList[i+1].c_str());

		int tRetNum = 0;
		if(tItemList[i] == "*")
		{
			tRetNum = tLeftNum * tRightNum;
		}
		else
		{
			if(0 != tRightNum)
				tRetNum = tLeftNum / tRightNum;
		}

		char tTempStr[32] = {0};
		itoa(tRetNum, tTempStr, 10);

		if((i-1) >= 0)
			tItemList[i-1] = "";

		tItemList[i] = "";

		if((i+1) < tItemList.size())
			tItemList[i+1] = string(tTempStr);
	}

	//将上面置为空的元素从vector中删除
	for(vector<string>::iterator tIter=tItemList.begin(); tIter!=tItemList.end(); )
	{
		if(*tIter == "")
			tIter = tItemList.erase(tIter);
		else
			tIter++;
	}

	//最后处理加减法
	for(int i=0; i<tItemList.size(); i++)
	{
		if(tItemList[i] != "+" && tItemList[i] != "-")
			continue;

		int tLeftNum	= 0;
		int tRightNum	= 0;
		if(i > 0)
			tLeftNum = atoi(tItemList[i-1].c_str());

		if(i < (tItemList.size()-1))
			tRightNum = atoi(tItemList[i+1].c_str());

		int tRetNum = 0;
		if(tItemList[i] == "+")
		{
			tRetNum = tLeftNum + tRightNum;
		}
		else
		{
			tRetNum = tLeftNum - tRightNum;
		}

		char tTempStr[32] = {0};
		itoa(tRetNum, tTempStr, 10);

		if((i-1) >= 0)
			tItemList[i-1] = "";

		tItemList[i] = "";

		if((i+1) < tItemList.size())
			tItemList[i+1] = string(tTempStr);
	}

	//将上面置为空的元素从vector中删除
	for(vector<string>::iterator tIter=tItemList.begin(); tIter!=tItemList.end(); )
	{
		if(*tIter == "")
			tIter = tItemList.erase(tIter);
		else
			tIter++;
	}

	//算式的结果必定存放在第一个位置
	if(tItemList.size() > 0)
		return atoi(tItemList[0].c_str());

	return 0;
}


    版本二:使用二叉树来构建算式,再通过中序便利来完成算式的计算

    

class Node
{
public:
	int		m_Num;
	string	m_Digit;

	Node*	m_Left;
	Node*	m_Right;

	Node()
	{
		m_Num	= 0;
		m_Digit = "";
		m_Left	= 0;
		m_Right = 0;
	}

	int getResult()
	{
		int tResult = 0;
		if(m_Digit != "")
		{
			int tLeftNum = 0;
			int tRightNum = 0;

			if(0 != m_Left && 0 != m_Right)
			{
				tLeftNum = m_Left->m_Num;
				if(m_Left->m_Digit != "")
				{
					tLeftNum = m_Left->getResult();
				}
			}

			if(0 != m_Right)
			{
				tRightNum = m_Right->m_Num;
				if(m_Right->m_Digit != "")
				{
					tRightNum = m_Right->getResult();
				}
			}

			if(m_Digit == "+") tResult = tLeftNum + tRightNum;
			if(m_Digit == "-") tResult = tLeftNum - tRightNum;
			if(m_Digit == "*") tResult = tLeftNum * tRightNum;
			if(m_Digit == "/" && tRightNum != 0) 
				tResult = tLeftNum / tRightNum;
		}
		else
		{
			tResult = m_Num;
		}

		return tResult;
	}
};


class Expre
{
private:
	Node* GetNode(string vStr)
	{
		Node* tRetNode = 0;
		if(0 == strncmp(vStr.c_str(), "#", 1))
		{
			tRetNode = (Node*)atoi(vStr.substr(1, vStr.length()-1).c_str());
		}
		else
		{
			tRetNode = new Node();
			tRetNode->m_Num = atoi(vStr.c_str());
		}

		return tRetNode;
	}

	Node* BuildTree(string vStr)
	{
		//识别算符与数字
		char* tPos = (char*)vStr.c_str();
		vector<string> tItemList;
		while((tPos-vStr.c_str()) < vStr.size())
		{
			while(*tPos == ‘ ‘)
				tPos++;

			if(*tPos == ‘(‘ || *tPos == ‘)‘ || *tPos == ‘+‘ || *tPos == ‘-‘ || *tPos == ‘*‘ || *tPos == ‘/‘)
			{
				string tTemp = " ";
				tTemp[0] = *tPos;
				tItemList.push_back(tTemp);

				tPos++;
			}
			else if(*tPos >= ‘0‘ && *tPos <= ‘9‘)
			{
				char* tTempPos = tPos;
				while(*tPos>=‘0‘&&*tPos<=‘9‘)
					tPos++; 

				tItemList.push_back(vStr.substr(tTempPos-vStr.c_str(), tPos-tTempPos));
			}
			else
				tPos++;
		}
		
		//递归,先处理括号子算式,再将结果的指针存放到临时vector
		vector<string> tTempList;
		int tLeftIndex = -1;
		int tLeftCount = 0;
		for(int i=0; i<tItemList.size(); i++)
		{
			if("(" == tItemList[i])
			{
				tLeftCount++;
				if(1 == tLeftCount)
					tLeftIndex = i;
			}
			else if(")" == tItemList[i])
			{
				tLeftCount--;
				if(0 == tLeftCount)
				{
					string tTempStr = "";
					for(int j=tLeftIndex+1; j<i; j++)
						tTempStr += tItemList[j];

					//将子树的地址转换为字符串保存起来,以便后续的处理
					Node* tRetNode = BuildTree(tTempStr);
					string tNodeAddr;
					tNodeAddr.resize(16);
					itoa((int)tRetNode, (char*)tNodeAddr.c_str(), 10);

					tTempList.push_back("#"+tNodeAddr);

					tLeftIndex = -1;
				}
			}
			else
			{
				if(0 == tLeftCount)
					tTempList.push_back(tItemList[i]);
			}
		}

		//这里是为了处理最外层是小括号的情况
		if(1 == tTempList.size())
		{
			return GetNode(tTempList[0]);
		}

		//到了这里就说明最外层不是小括号了
		tLeftIndex = 0;
		Node* tLastRootNode = 0;
		for(int j=0; j<tTempList.size(); j++)
		{
			if("+" != tTempList[j] && "-" != tTempList[j])
				continue;
			
			Node* tLeftRootNode = 0;
			Node* tRightRootNode = 0;

			int tRightIndex = j+1;
			while(tRightIndex<tTempList.size() && tTempList[tRightIndex] != "+" && tTempList[tRightIndex] != "-")
				tRightIndex++;

			//处理左边算式
			for(int w=tLeftIndex; w<j; w++)
			{
				if(tTempList[w] == "*" || tTempList[w] == "/")
				{
					Node* tRightNode = GetNode(tTempList[w+1]);

					Node* tRootNode = new Node();
					tRootNode->m_Digit = tTempList[w];
					tRootNode->m_Right = tRightNode;

					if(tLeftRootNode != 0)
					{
						tRootNode->m_Left = tLeftRootNode;
					}
					else
					{
						tRootNode->m_Left = GetNode(tTempList[w-1]);
					}

					tLeftRootNode = tRootNode;
					w++;
				}
				else
				{
					tLeftRootNode = GetNode(tTempList[w]);
				}
			}

			//处理右边算式
			for(int w=j+1; w<tRightIndex; w++)
			{
				if(tTempList[w] == "*" || tTempList[w] == "/")
				{
					Node* tRightNode = GetNode(tTempList[w+1]);

					Node* tRootNode = new Node();
					tRootNode->m_Digit = tTempList[w];
					tRootNode->m_Right = tRightNode;

					if(tRightRootNode != 0)
					{
						tRootNode->m_Left = tRightRootNode;
					}
					else
					{
						tRootNode->m_Left = GetNode(tTempList[w-1]);
					}

					tRightRootNode = tRootNode;
					w++;
				}
				else
				{
					tRightRootNode = GetNode(tTempList[w]);
				}
			}

			//将左右子树组合起来
			if(0 == tLastRootNode)
			{
				tLastRootNode = new Node();
				tLastRootNode->m_Digit	= tTempList[j];
				tLastRootNode->m_Left	= tLeftRootNode;
				tLastRootNode->m_Right	= tRightRootNode;
			}
			else
			{
				Node* tTempNode = new Node();
				tTempNode->m_Digit	= tTempList[j];
				tTempNode->m_Left	= tLastRootNode;
				tTempNode->m_Right	= tRightRootNode;

				tLastRootNode = tTempNode;
			}

			//这里重置变量值,j的赋值有点难理解
			tLeftIndex = tRightIndex;
			j = tRightIndex-1;
		}

		return tLastRootNode;
	}

public:
	int GetResult(string vStr)
	{
		Node* tRetNode = BuildTree(vStr);
		if(0 == tRetNode)
			return 0;

		int tResult = tRetNode->getResult();

		vector<DWORD> tNodeAddrVector;
		tNodeAddrVector.push_back((DWORD)tRetNode);

		//为了不写递归去释放内存,这里使用vector来处理
		for(int i=0; i<tNodeAddrVector.size(); i++)
		{
			if(0 != ((Node*)tNodeAddrVector[i])->m_Left)
				tNodeAddrVector.push_back((DWORD)((Node*)tNodeAddrVector[i])->m_Left);

			if(0 != ((Node*)tNodeAddrVector[i])->m_Right)
				tNodeAddrVector.push_back((DWORD)((Node*)tNodeAddrVector[i])->m_Right);

			delete (Node*)tNodeAddrVector[i];
		}

		return tResult;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	Expre tTest;
	printf("result=%d\n", Expr("(-1+2)*3+4"));
        return 0;
}
     想想都觉得自卑,人家大一的时候就实现了计算器。这个只是一个联系的习题吧,当做是最近的一个练手,主要是锻炼自己思考和解决问题的能力。

一次计算器的练习

标签:

原文地址:http://my.oschina.net/dragonblog/blog/380339

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!