Если вы действительно хотите иметь возможность хранить различные типы в каждом узле, вам понадобится индикатор в самом узле, чтобы определить, какой тип полезной нагрузки. Что-то вроде:
typedef enum {
TYP_STRING,
TYP_INT,
TYPE_FLOAT
} tNodeType;
struct treenode {
tNodeType typ;
void* data;
TreeNode left, right;
};
Ваша функция сравнения должна сначала взглянуть на тип. Если типы разные, узлы разные. Если типы совпадают, вам нужно сравнить узлы на основе типа. С головы до головы, поэтому, возможно, потребуется отладка:
int compareNodes (TreeNode a, TreeNode b) {
if (a->typ != b->typ) return FALSE;
switch (a->typ) {
case TYP_STRING: {
return (strcmp ((char*)(a->data), (char*)(b->data)) == 0);
}
case TYP_INT: {
return (*((int*)(a->data)) == *((int*)(b->data));
}
case TYP_FLOAT: {
return (*((float*)(a->data)) == *((float*)(b->data));
}
}
return FALSE;
}
Если вам не нужно хранить различные типы в дереве, тогда тип (и функция сравнения) принадлежат дереву, а не каждому узлу. Это обычный случай, хотя, безусловно, возможно иметь дерево, содержащее разные типы, - это лишь немного усложняет код.