1

我想在 C 中创建一个函数树,如下所示: http ://scr.hu/5rq/vdja0

所以基本上我希望结果是这样的:http ://scr.hu/5rq/f04uu

wherex是我可以提供的变量(浮点数)。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);但未运行的函数的东西,而不是具有给定参数的函数的确切值,以及 where Function1()orFunction2()表示将两个参数相除或相乘的函数等等。

不,这不是为了学校,是的,这是我使用基因编程的悲惨尝试。

4

2 回答 2

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 *并在您想要调用它们时将它们转换为正确的函数指针类型。

于 2012-07-16T19:28:49.083 回答
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
于 2012-07-16T20:14:58.137 回答