我正在用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个节点。
答案 0 :(得分:1)
我认为Node
或Tree
不是第一个写的类。
我从Expression
开始。在您的情况下,您至少需要一个BinaryExpression
,以及一个没有子节点(常量或变量)的表达式。每个二进制表达式应包含auto_ptr<Expression> lhs
和auto_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
因此,当您进行交叉或变异并且想要选择随机节点时,您只需执行以下操作:
在这种情况下,您无需了解有关节点父节点的任何信息。所以交配/突变应该是这样的:
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;
...
}
通过跳转到sequentialFirst
或sequentialLast
,然后迭代地转到sequentialNext
或sequentialPrevious
,您将在节点上双向移动。当然,必须正确实现Node
构造函数和析构函数,以使这些指针保持最新。