标签:
我的个人博客( 肥龙的博客)发表了新文章了!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