表达式树实现问题

时间:2017-04-25 14:24:35

标签: c++ data-structures expression binary-tree arithmetic-expressions

我正在努力构建一个表达式树头,特别是treenodes的指针,我不知道如何实现并实际创建节点来存储数据,这应该是非常基本的但是代码让我很困惑。

例如,当我想创建一个5 + 5的表达式时,它应该是这样的:

  +
 / \
5   5

然而,当实施这个时,我不知道如何开始。如何获取根节点中的运算符和作为子节点的数字?我知道我可以将它们存储在堆栈中并从顶部读取,但是设置的父,左子和右子方法只接受(TreeNode *)参数,而向量标记是类型字符串。

TreeNode的构造函数也采用整数和运算符值,为什么呢?我如何以root,parent和children的形式将这些值放入各自的节点?

ExprTree.cpp

    #include "ExprTree.h"
    #include <sstream>
    #include <iostream>

    TreeNode * createOperatorNode(const string & op){

      if (op == "+") return new TreeNode(Plus);
      if (op == "-") return new TreeNode(Minus);
      if (op == "*") return new TreeNode(Times);
      if (op == "/") return new TreeNode(Divide);
      return new TreeNode(NoOp);

    }

    /*
     * Basic constructor that sets up an empty Expr Tree.
     */
    ExprTree::ExprTree(){

        this->root = NULL;
       this-> _size = 0;

    }

    /*
     * Constructor that takes a TreeNode and sets up an ExprTree with that node at the root.
     */
    ExprTree::ExprTree(TreeNode * r){

        this->root = r;
    }

    ExprTree ExprTree::buildTree(vector<string> tokens){ 

// the tokens are the broken up arithimec expression
i.e 
5 
+ 
5
// not sure what to do here, i've tried using stacks but i wasn't sure how to get the stored data into the nodes.

    }

TreeNode.cpp

#include "TreeNode.h"

TreeNode::TreeNode(Operator o){
  op = o;
  parent = 0;
  leftChild = 0;
  rightChild = 0;
}

TreeNode::TreeNode(int val){
  op = Value;
  value = val;
  parent = 0;
  leftChild = 0;
  rightChild = 0;
}

TreeNode.h

#include <string>
#include <sstream>

enum Operator {Value, Plus, Minus, Times, Divide, NoOp};

class TreeNode {

 private:

  Operator op; //If this node represents an operator, this is where it's stored.
               //It can take values from the Operator enum (i.e. Plus, Minus, etc.)
               //If it represents a value, use the Value value. :D
  int value; //If this node stores an actual number, this is it.

  TreeNode * parent; //Pointer to the parent.
  TreeNode * leftChild; //Pointer to the left child of this node.
  TreeNode * rightChild; //Pointer to the right child of this node.

 public:

  TreeNode(Operator); //Constructor to use for +, -, * and /.
                      //Example: TreeNode(Plus);
  TreeNode(int); //Constructor to use for actual numbers.
                 //Example: TreeNode(5);
  void setParent(TreeNode *); //Set the parent pointer.
  void setLeftChild(TreeNode *); //Set the left child pointer.
  void setRightChild(TreeNode *); //Set the right child pointer.
  TreeNode * getParent(); //Get the parent pointer.
  TreeNode * getLeftChild(); //Get the left child pointer.
  TreeNode * getRightChild(); //Get the right child pointer.
  int getValue(); //Returns the stored value;
  Operator getOperator(); //Returns the stored operator.
  bool isValue(); //Returns true if this node is a Value node.
  bool isOperator(); //Returns truee if this node is Plus, Minus, Times or Divide node.
  std::string toString(); //Returns a simple string representation of the node.

};

3 个答案:

答案 0 :(得分:0)

解析表达式的最简单方法是构建递归下降解析器。它由称为表达式,术语和因子的相互递归函数组成。因子是最小单位,可以是基本数字,也可以是括号,表达式,近括号(因此相互递归进入)。术语是乘法和除法运算符的因子集合,表达式是由加号和减号运算符连接的术语集合。

你需要一个特殊规则来减少一元。

现在递归下降解析器实际上并没有将树构建为内存中的结构。树在调用模式中隐含。但是,如果你想要一棵树,你可以很容易地修改它来构建一棵树。

查看我非常简单的Basic解释器

可能会有所帮助

https://github.com/MalcolmMcLean/minibasic

答案 1 :(得分:0)

您只需使用TreeNode.h为您提供的内容。

例如,如果你想创建一个名为root的树,代表5 + 5,你就像

TreeNode root(Plus);
root.setLeftChild(new TreeNode(5));
root.setRightChild(new TreeNode(5));

在解析器中,好吧,尝试构建一个。请注意,您可以通过跟踪子指针和父指针轻松遍历树。

另一种方法是在字符串上创建一个构造函数,它作为最外层的运算符进行求值,然后通过给它们提供适当的子字符串来递归地构造它的子句,比如

TreeNode::TreeNode(string expression){

    if(expression is number){
        create this as number node
    }
    create this as operator node with outermost operator
    split string by outermost operator
    set left child to left side of split string
    set right child to ...
}

那就是说,作为评论,我没有看到~TreeNode()被定义,这意味着你将有内存泄漏。

另外,我建议分离Tree和TreeNode,即创建一个TreeNode作为内部类的类Tree,TreeNode的构造函数和析构函数是私有的(Tree作为朋友)。让您更好地控制事物。如果操作不正确,setLeftChild等操作可能会对内存泄漏造成危险,并且可以创建循环(这违背了树的想法)。

答案 2 :(得分:0)

首先,将表达式转换为后缀表达式(Infix To Postfix)。

表达式: 5 + 5

后缀: 5 5 +

然后解析后缀字符串,每当找到操作数将其推入堆栈时,或者如果找到运算符,则从堆栈中弹出两个操作数(如果它是二进制运算符),然后分配树根作为左边和左边的操作员正确的孩子作为操作员。

Tree *t;
Stack<string> stack;

// parsing the tokens(expression)...
for(int i=0; i<token[i].length(); i++) {
    if(token[i] == "+" || token[i] == "-" || token[i] == "*" || token[i] == "/") {
        string op1 = stack.top(); stack.pop();
        string op2 = stack.top(); stack.pop();
        t->root = new createOperatorNode(token[i]);
        t->leftChild = new TreeNode(op1);
        t->rightChild = new TreeNode(op2);
    }
    else {
        stack.push(token[i]);
    }
}