【问题标题】:Build a binary tree from an infix expression without using a stack不使用堆栈从中缀表达式构建二叉树
【发布时间】:2015-04-06 09:42:22
【问题描述】:

最近我给convert an infix expression to a binary tree without using any stack写了一个算法。然而,当我在网上搜索时,我发现那里描述的算法都是基于堆栈(或递归)的。

所以我开始担心我的算法的正确性,尽管我无法证明 还是不正确。

问题

您知道在技术上是否可以在没有任何堆栈的情况下进行转换?我的算法错了吗?

简短说明

它基于:

  1. 中缀表达式中的操作数要么属于它前面的运算符的右孩子,要么属于它后面的运算符的左孩子。

  2. 如果运算符OP2的优先级高于其前一个运算符OP1,则前一个运算符x成为OP2的左孩子,OP2成为OP1的右孩子.

  3. 如果运算符 OP2 的优先级低于其前面的运算符 OP1,则前面的操作数 x 将成为 OP1 的右孩子。从OP1 上树,比较OP1OP2 的每个祖先的优先级,直到OP2 OP。然后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 并没有错。

标签: c++ algorithm


【解决方案1】:

这是你的堆栈:

while (p->precedence <= q->precedence) q = q->parent;

【讨论】:

  • 啊哈!我知道有人会这么说 :) 我在每个节点中都使用了一个父字段,与堆栈相比,它不一定能节省内存。
  • 上移步骤的行为确实类似于堆栈的弹出操作,但无论如何它并不能完全模拟堆栈的所有操作。它的优点是不使用树以外的其他数据结构。
猜你喜欢
  • 2012-11-26
  • 1970-01-01
  • 1970-01-01
  • 2014-05-10
  • 1970-01-01
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多