【发布时间】:2015-04-06 09:42:22
【问题描述】:
最近我给convert an infix expression to a binary tree without using any stack写了一个算法。然而,当我在网上搜索时,我发现那里描述的算法都是基于堆栈(或递归)的。
所以我开始担心我的算法的正确性,尽管我无法证明 还是不正确。
问题
您知道在技术上是否可以在没有任何堆栈的情况下进行转换?我的算法错了吗?
简短说明
它基于:
中缀表达式中的操作数要么属于它前面的运算符的右孩子,要么属于它后面的运算符的左孩子。
如果运算符
OP2的优先级高于其前一个运算符OP1,则前一个运算符x成为OP2的左孩子,OP2成为OP1的右孩子.如果运算符
OP2的优先级低于其前面的运算符OP1,则前面的操作数x将成为OP1的右孩子。从OP1上树,比较OP1和OP2的每个祖先的优先级,直到OP2OP。然后OP2成为OP的右孩子。
程序
#include <iostream>
#include <string>
#include <sstream>
#include <cassert>
using namespace std;
typedef struct Node{
// store operator or operand
string data;
// only valid for operator
int precedence;
struct Node* parent;
struct Node* left;
struct Node* right;
}CNode, *PNode;
PNode CreateNode(const string& x)
{
PNode p = new CNode;
p->parent = p->left = p->right = NULL;
p->data = x;
return p;
}
bool IsOperator(const string& x)
{
// Since the only impact of parentheses () is on precedence,
// they are not considered as operators here
return ((x.length() == 1) &&
(x[0] == '*' ||
x[0] == '/' ||
x[0] == '+' ||
x[0] == '-'));
}
bool IsLeftParenthesis(const string& x)
{
return x == "(";
}
bool IsRightParenthesis(const string& x)
{
return x == ")";
}
bool IsOperand(const string& x)
{
int y;
stringstream ss(x);
if (ss >> y) return true;
else return false;
}
int GetPrecedence(const string& x)
{
assert(IsOperator(x));
if (x[0] == '*' || x[0] == '/') return 2;
else return 1;
}
PNode CreateInfixTree(const string& exp)
{
// create a dummy root with minimal precedence
// its content is trivial
PNode root = CreateNode("0");
root->precedence = INT_MIN;
// the previous operand of current operator
PNode preOperand = NULL;
// the previous operator of current operator
PNode preOperator = root;
// the impact of preceding parenthesis, if any
int correction = 0;
string token;
stringstream ss(exp);
while (ss >> token)
{
if (IsOperand(token))
{
preOperand = CreateNode(token);
}
else if (IsOperator(token))
{
PNode p = CreateNode(token);
p->precedence = GetPrecedence(token) + correction;
if (p->precedence > preOperator->precedence)
{
p->left = preOperand;
preOperator->right = p;
p->parent = preOperator;
}
else
{
preOperator->right = preOperand;
PNode q = preOperator->parent;
while (p->precedence <= q->precedence) q = q->parent;
p->left = q->right;
q->right = p;
p->parent = q;
}
preOperand = NULL;
preOperator = p;
}//else if (IsOperator(token)
else if (IsLeftParenthesis(token))
{
correction += 2;
}
else if (IsRightParenthesis(token))
{
correction -= 2;
}
else
{
cout << "illegal token found: " << token << endl;
break;
}
}//while
if (preOperand == NULL)
cout << "illegal expression: cannot end with operator: "
<< preOperator->data << endl;
else preOperator->right = preOperand;
// delete dummy root
PNode realRoot = root->right;
delete root;
if (realRoot) realRoot->parent = NULL;
return realRoot;
}
void PostOrderPrintTree(PNode node)
{
if (node)
{
PostOrderPrintTree(node->left);
PostOrderPrintTree(node->right);
cout << node->data << " ";
}
}
int main()
{
// valid operators: + - * / ( )
// valid operands: integers
// whitespace separated as: ( 1 + 2 ) * 3
string exp;
getline(cin, exp);
PNode root = CreateInfixTree(exp);
PostOrderPrintTree(root);
cout << endl;
}
【问题讨论】:
-
就像需要注意的一样,如果你有一个非法的表达式,你的算法将继续运行。
-
另外,这很酷。根据你对算法的了解,它可以用来处理一元运算符之类的吗?
-
@Seth,对,这句话我没有过多处理非法表达。目前它只支持二元运算符和括号。
-
这不是 C++ 代码,这是带有非常小的 C++ 外衣的 C 代码。
-
@Sjoerd 并没有错。