#ifndef Expression_H
#define Expression_H
#include "List.h"
#include "Stack.h"
#define INFIX 0
#define POSTFIX 1
#define OPND 4
#define OPTR 8
template class ExpNode
{
public:
int type;
union { Type opnd; char optr;};
ExpNode() : type(INFIX), optr('=') {}
ExpNode(Type opnd) : type(OPND), opnd(opnd) {}
ExpNode(char optr) : type(OPTR), optr(optr) {}
};
{
public:
void Input()
{
MakeEmpty(); Get()->type =INFIX;
cout << endl << "输入表达式,以=结束输入" << endl;
Type opnd; char optr = ' ';
while (optr != '=')
{
cin >> opnd;
if (opnd != 0)
{
ExpNode newopnd(opnd);
LastInsert(newopnd);
}
cin >> optr;
ExpNode newoptr(optr);
LastInsert(newoptr);
}
}
void Print()
{
First();
cout << endl;
for (ExpNode *p = Next(); p != NULL; p = Next() )
{
switch (p->type)
{
case OPND:
cout << p->opnd; break;
case OPTR:
cout << p->optr; break;
default: break;
}
cout << ' ';
}
cout << endl;
}
Expression & Postfix() //将中缀表达式转变为后缀表达式
{
First();
if (Get()->type == POSTFIX) return *this;
Stack s; s.Push('=');
Expression temp;
ExpNode *p = Next();
while (p != NULL)
{
switch (p->type)
{
case OPND:
temp.LastInsert(*p); p = Next(); break;
case OPTR:
while (isp(s.GetTop()) > icp(p->optr) )
{
ExpNode newoptr(s.Pop());
temp.LastInsert(newoptr);
}
if (isp(s.GetTop()) == icp(p->optr) )
{
s.Pop(); p =Next(); break;
}
s.Push(p->optr); p = Next(); break;
default: break;
}
}
*this = temp;
pGetFirst()->data.type = POSTFIX;
return *this;
}
Type Calculate()
{
Expression temp = *this;
if (pGetFirst()->data.type != POSTFIX) temp.Postfix();
Stack s; Type left, right;
for (ExpNode *p = temp.Next(); p != NULL; p = temp.Next())
{
switch (p->type)
{
case OPND:
s.Push(p->opnd); break;
case OPTR:
right = s.Pop(); left = s.Pop();
switch (p->optr)
{
case '+': s.Push(left + right); break;
case '-': s.Push(left - right); break;
case '*': s.Push(left * right); break;
case '/': if (right != 0) s.Push(left/right); else return 0; break;
// case '%': if (right != 0) s.Push(left%right); else return 0; break;
// case '^': s.Push(Power(left, right)); break;
default: break;
}
default: break;
}
}
return s.Pop();
}
private:
int isp(char optr)
{
switch (optr)
{
case '=': return 0;
case '(': return 1;
case '^': return 7;
case '*': return 5;
case '/': return 5;
case '%': return 5;
case '+': return 3;
case '-': return 3;
case ')': return 8;
default: return 0;
}
}
int icp(char optr)
{
switch (optr)
{
case '=': return 0;
case '(': return 8;
case '^': return 6;
case '*': return 4;
case '/': return 4;
case '%': return 4;
case '+': return 2;
case '-': return 2;
case ')': return 1;
default: return 0;
}
}
};
#endif
几点说明
l 表达式用单链表储存,你可以看到这个链表中既有操作数又有操作符,如果你看过我的《如何在一个链表中链入不同类型的对象》,这里的方法也是对那篇文章的补充。
l 输入表达式时,会将原来的内容清空,并且必须按照中缀表示输入。如果你细看一下中缀表达式,你就会发现,除了括号,表达式的结构是“操作数”、“操作符”、“操作数”、……“操作符(=)”,为了统一这个规律,同时也为了使输入函数简单一点,规定括号必须这样输入“0(”、“)0”;这样一来,“0”就不能作为操作数出现在表达式中了。因为我没有在输入函数中增加容错的语句,所以一旦输错了,那程序就“死”了。
l 表达式求值的过程是,先变成后缀表示,然后用后缀表示求值。因为原书讲解的是这两个算法,并且用这两个算法就能完成中缀表达式的求值,所以我就没写中缀表达式的直接求值算法。具体算法说明参见原书,我就不废话了。
l Calculate()注释掉的两行,“%”是因为只对整型表达式合法,“^”的Power()函数没有完成。
l isp(),icp()的返回值,原书说的不细,我来多说两句。‘=’(表达式开始和结束标志)的栈内栈外优先级都是最低。‘(’栈外最高,栈内次最低。‘)’栈外次最低,不进栈。‘^’栈内次最高,栈外比栈内低。‘×÷%’栈内比‘^’栈外低,栈外比栈内低。‘+-’栈内比‘×’栈外低,栈外比栈内低。这样,综合起来,就有9个优先级,于是就得出了书上的那个表。(CSDN)