Each type of node is a subclass of the Node class. The two non-terminal node classes are Binary_Node and Unary_Node. They are basically identical, with the obvious exception of the number of children. All additional functions provided in these classes are mainly used for access to private fields and are self-explanatory. Constructors for each subclass take a pointer to the parent node, along with the operator or terminal that will be associated with the new node. Descriptions of the two classes:
// binary operation node
class Binary_Node : public Node {
private:
Node *left; // left child
Node *right; // right child
Binary_Func *f; // the function of this node
public:
// constructor takes the parent and the function
Binary_Node(Node *,Binary_Func *);
~Binary_Node(void); // destructor will delete the children
// adds a node to the left
void set_left(Node *l) {left = l;};
// adds a node to the right
void set_right(Node *r) {right = r;};
// accesses the left child
Node *get_left(void) {return left;};
// accesses the right child
Node *get_right(void) {return right;};
// accesses the function
Binary_Func *get_func(void) {return f;};
double fitness; // fitness of the tree (if this is the root)
// value function just needs to pass the values of the children to
// f
Val value(void); // value function
int count(void); // counter function
Node *find(int); // finder function
char *print(void); // printer function
};
// unary operation node
class Unary_Node : public Node {
private:
Node *child; // the (single) child
Unary_Func *f; // the function of this node
public:
// constructor takes the parent and the function
Unary_Node(Node *,Unary_Func *);
~Unary_Node(void); // destructor will delete the child
// adds a child node
void set_child(Node *c) {child = c;};
// accesses the child node
Node *get_child(void) {return child;};
// accesses the function
Unary_Func *get_func(void) {return f;};
// value function just passes the value of the child to f
Val value(void); // value function
int count(void); // counter function
Node *find(int); // finder function
char *print(void); // printer function
};
The value of these types of nodes is obtained by simply calling the
operator with the values of each child. For example, the value
function of the Binary_Node class:
// value function - pretty simple, just evaluate the function using the
// left and right children's values
Val Binary_Node::value(void)
{
// if the left or right does not exist, generate an error and return
// zero
if ((!left) || (!right)) {
fprintf(stderr,"A binary node is missing a child!\n");
return (Val)0;
}
// return it
return (f->eval(left->value(),right->value()));
}
Terminal nodes may contain either constants or variables; these are
represented by the Terminal_Const and Terminal_Var
classes. These two subclasses are only slightly different:
// a constant value terminal node
class Terminal_Const : public Node {
private:
Val constant; // the constant value
public:
// constructor takes the parent and value
Terminal_Const(Node *, Val);
// the value function just needs to return the constant
Val value(void) {return constant;};
// counter function is just 1 for this node
int count(void) {return 1;};
Node *find(int); // finder function
char *print(void); // printer function
};
// variable terminal node. uses a Val ref for the value
class Terminal_Var : public Node {
private:
Variable *var; // ref of the variable value
public:
// constructor takes parent and variable pointer
Terminal_Var(Node *, Variable *);
// the value function just returns the current variable value
Val value(void) {return *var->var;};
// this returns the value pointer (for copying)
Variable *val_p(void) {return var;};
// counter function is just 1 for this node
int count(void) {return 1;};
Node *find(int); // finder function
char *print(void); // printer function
};