2012-07-16 5 views
1

Я хочу, чтобы дерево функций в C, который будет выглядеть следующим образом: http://scr.hu/5rq/vdja0Создание дерева функций в C

Поэтому в основном я хочу, чтобы результат как это: http://scr.hu/5rq/f04uu

где x это переменная, которую я могу предоставить (float). 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

Похоже, вы пытаетесь достичь динамической оценки выражения. Означает ли это вашу проблему? Вам было бы легче сделать это на объектно-ориентированном языке. – Wug

ответ

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; 
}; 

Если вы хотите, чтобы иметь структуру, которая содержит различные типы функций (которые могут иметь различные типы возврата или принимать различные параметры), вы можете просто хотите сохранить й em как void * и направить их на нужный тип указателя функции, если вы хотите их вызвать.

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; 
} 

Затем вы копируете все свои прототипы в некоторый заголовочный файл и # включаете его там, где вам это нужно. Вы сможете построить цепочки выражений и оценить их следующим образом:

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 
Смежные вопросы