如何构造这个节点树?

时间:2010-07-11 14:40:18

标签: c++ typedef

我正在用C ++编写一个程序,它使用遗传技术来优化表达式树。

我正在尝试编写一个具有数据成员Tree的类Node root。节点构造函数生成一个随机节点树,其中+-*/作为节点,整数作为叶子。

我一直在研究这个问题,我还不清楚最好的结构。因为我需要访问树中的任何节点以便变异或杂交树,所以我需要保留节点的序列。数组可以,但似乎vector是推荐的容器。

vector<Node> dict;

因此Tree类将包含一个向量dict,其中包含树的所有节点(或指向相同的指针),树的根节点以及用于保存树的适应度量的变量。 / p>

class Tree
    {
    public:
        typedef vector<Node>dict;
        dict v;
        Node *root;
        float fitness;

        Tree(void);
        ~Tree();
    };

class Node
    {
    public:
        char *cargo;
        Node *parent;
        Node *left;
        Node *right;
        bool entry;
        dict v;
        Node(bool entry, int a_depth, dict v, Node *pparent = 0);
                };

Tree::Tree()
    {
     Node root(true,  tree_depth, v);
    };

似乎没有放置typedef vector<Node>dict;的好地方,因为如果它在Tree的定义中,它不知道Node,并且会给出错误说明。我找不到typedef的地方了。

但我甚至不确定矢量是否是最好的容器。节点只需要连续编入索引。容器需要增长,因为可能有200到500个节点。

3 个答案:

答案 0 :(得分:1)

我认为NodeTree不是第一个写的类。

我从Expression开始。在您的情况下,您至少需要一个BinaryExpression,以及一个没有子节点(常量或变量)的表达式。每个二进制表达式应包含auto_ptr<Expression> lhsauto_ptr<Expression> rhs

然后,您可以轻松编写一个函数来枚举表达式树的成员。如果性能变得相关,则可以在树中缓存表达式列表,并在更改表达式时手动使其无效。任何更高级的东西都可能更慢,更容易出错。

我不明白为什么表达式需要知道它的父表达式。只有在开始编辑表达式时才会使生活更加艰难。

答案 1 :(得分:1)

我认为标准二进制树应该...这里是example of a (binary) expression tree node

const int NUMBER = 0,    // Values representing two kinds of nodes.
          OPERATOR = 1;

struct ExpNode {  // A node in an expression tree.

    int kind;        // Which type of node is this?
                     //   (Value is NUMBER or OPERATOR.)
    double number;   // The value in a node of type NUMBER.
    char op;         // The operator in a node of type OPERATOR.
    ExpNode *left;   // Pointers to subtrees,
    ExpNode *right;  //     in a node of type OPERATOR.

    ExpNode( double val ) {
          // Constructor for making a node of type NUMBER.
       kind = NUMBER;
       number = val;
    }

    ExpNode( char op, ExpNode *left, ExpNode *right ) {
          // Constructor for making a node of type OPERATOR.
       kind = OPERATOR;
       this->op = op;
       this->left = left;
       this->right = right;
    }

}; // end ExpNode

因此,当您进行交叉或变异并且想要选择随机节点时,您只需执行以下操作:

  1. 计算树中的节点数(只需要在构造函数中执行此操作)。
  2. 选择从0到树大小的随机索引。
  3. 访问每个节点并从随机索引中减去1,直到达到零。
  4. 索引为0时返回节点。
  5. 在这种情况下,您无需了解有关节点父节点的任何信息。所以交配/突变应该是这样的:

    select nodeX
    select nodeY
        if( Rand(0,1) == 1 )
            nodeY->left = nodeX;
        else
            nodeY->right = nodeX;
    

    那应该是它......

答案 2 :(得分:0)

您可以在节点上实现列表。然后,每个节点内部将有两个额外的指针:

class Node{
...
Node* sequentialPrevious;
Node* sequentialNext;
...
}

树也是如此:

class Tree{
...
Node* sequentialFirst;
Node* sequentialLast;
...
}

通过跳转到sequentialFirstsequentialLast,然后迭代地转到sequentialNextsequentialPrevious,您将在节点上双向移动。当然,必须正确实现Node构造函数和析构函数,以使这些指针保持最新。