我想在C中创建一个函数树,它看起来像这样: http://scr.hu/5rq/vdja0
基本上我希望结果如下:http://scr.hu/5rq/f04uu
其中x
是我可以提供的变量(浮点数)。 F0到F6是随机函数,它有两个参数(函数如乘法,加法或给出随机数)。
所以我的确切问题是:我怎么能这样做?
我知道可以通过存储数组中每个函数给出的精确值来轻松完成。
但是当谈到获得不同的“x”值时,它会变得复杂。
我最初的想法是创建函数,将随机函数附加到树中的每个节点,但是,我不确定应该如何完成构成该树的结构,
typedef struct drzewo typ;
struct drzewo {
typ *right;
typ *left;
typ *up;
float *value; //what to do with this ?
};
我想以某种方式改变行“float * value;”可以存储像Function1(left->value,right->value);
但没有运行的函数的东西,而不是给定参数的函数的确切值,并且Function1()
或Function2()
表示将两个参数分开或将它们相乘的函数或等等。
不,这不是为了学校,是的,这是我使用遗传编程的悲惨尝试。
答案 0 :(得分:5)
要创建指向函数的类型,请使用函数原型并将函数名替换为(*<typename>)
。因此,如果您的函数foo
看起来像:
float foo( int arg1, char *arg2 );
您可以创建一个类型“foo_fn”,它是一个指向函数的指针,如foo:
typedef float (*foo_fn)( int, char * );
然后将其存储在您的结构中:
typedef struct drzewo typ;
struct drzewo {
typ *right;
typ *left;
typ *up;
foo_fn fn_ptr;
};
如果你想拥有一个包含各种类型函数的结构(可能有不同的返回类型或采用不同的参数),你可能只想将它们存储为void *
并将它们转换为正确的函数指针当你想打电话时输入。
答案 1 :(得分:0)
您可以从以下内容开始:
typedef enum Operation
{
VALUE, // 0 argument (uses value)
NOT, SIN, COS, TAN // 1 argument
ADD, SUB, DIV, MUL, POW, LOG, AND, OR, XOR, // 2 argument
SENTINEL; // the last element
}
Operation;
typedef struct ExprNode
{
Operation op;
struct ExprNode * left;
struct ExprNode * right;
float value;
}
ExprNode;
typedef float (* EvalFunc)(ExprNode *);
EvalFunc eval_array[SENTINEL]; // array size is number of operations in enum
然后你可以把它放到某种通用的包装器函数中,然后从你的特殊用途EvalFunc函数调用那个包装器,你将在一分钟内写出来:
float EVAL(ExprNode * node)
{
return eval_array[node->op](node);
}
// for bonus points, use a #define
// #define EVAL(node) eval_array[node->op](node)
从那里开始,你需要一堆带有与EvalFunc匹配的签名的函数,比如这个最简单的函数,它适合与VALUE说明符一起使用:
float Eval_Value(ExprNode * node)
{
return node->value;
}
或者这个稍微深一点(但仍然很简单)一个,那就是增加:
float Eval_Add(ExprNode * node)
{
return EVAL(node->left) + EVAL(node->right);
}
您现在可以将所有这些函数放入eval_array
数组中,以便您可以使用索引查找快速调用它们,如下所示:
eval_array[VALUE] = &Eval_Value;
eval_array[ADD] = &Eval_Add;
// etc
您可能希望为ExprNodes包含某种初始化函数,以便从初始化它们中解除乏味:
ExprNode_init(ExprNode * node, Operation _op, float _value, ExprNode * _left, ExprNode * _right)
{
node->op = _op;
node->left = _left;
node->right = _right;
node->value = _value;
}
然后,将所有原型复制到某个头文件中,并在需要的地方#include它。您将能够构建表达式链并以下列方式对其进行评估:
ExprNode n1, n2, n3, X, Y, Z;
ExprNode_init(&n1, SUM, 0, &n2, &n3 ); // expression nodes: value is ignored
ExprNode_init(&n2, MUL, 0, &X, &Y ); // some functions only require 1 arg
ExprNode_init(&n3, DIV, 0, &Z, &Y ); // right can be omitted for these
ExprNode_init(&X, VALUE, 3, NULL, NULL); // value nodes: value is not ignored
ExprNode_init(&Y, VALUE, 4, NULL, NULL); // left and right are both ignored
ExprNode_init(&Z, VALUE, 6, NULL, NULL); // both can be null
float result = EVAL(n1); // X*Y + Z/Y : X=3, Y=4, Z=6; should be 13.5