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