C 带stdin的N元树函数(makenode,insert)
我试着编写以下函数C 带stdin的N元树函数(makenode,insert),c,algorithm,tree,C,Algorithm,Tree,我试着编写以下函数 typedef struct node{ char *name; int n; //number of kids struct node **kids; int dtype; // COMPOSITE or BASIC union data{ double price; //for BASIC char *quantity; //for COMPOSITE }data; }node; void
typedef struct node{
char *name;
int n; //number of kids
struct node **kids;
int dtype; // COMPOSITE or BASIC
union data{
double price; //for BASIC
char *quantity; //for COMPOSITE
}data;
}node;
void create_kid(node **parent){
if(*parent == NULL){
(*parent) = malloc(sizeof(node));
(*parent)->n = 0;
(*parent)->kids = NULL;
}else{
(*parent)->n += 1;
(*parent)->kids = realloc((*parent)->kids, ((*parent)->n)*(sizeof(node)));
(*parent)->kids[(*parent)->n - 1] = malloc(sizeof(node));
(*parent)->kids[(*parent)->n - 1]->n = 0;
(*parent)->kids[(*parent)->n - 1]->kids = NULL;
}
}
void insert_c(node *node, char *str){
node->name = malloc(MAX);
node->name = str;
node->dtype = COMPOSITE;
}
void insert_b(node *node, char *str){
node->name = malloc(MAX);
node->name = str;
node->dtype = BASIC;
}
用这样的输入生成这样的n元树
BIKE(2*WHEEL(RIM[60.0 ],
2*AXLE,
SPOKE[120.],
HUB(2*GEAR[25.],AXLE(5*BOLT[0.1], 7 * NUT[.15]))),
FRAME(REARFRAME [175.00],
1*FRONTFRAME (FORK[22.5] ,AXLE, 2 *HANDLE[10.])))
我知道n元树的另一种表示法,包括*兄弟姐妹和*第一个孩子,但我相信**孩子的表示法更适合我的情况。我想问几个问题
首先,功能有什么问题吗?它们是否适合构建n元树
其次,即使我得到了正确的函数,我也不能从输入中构造树。例如,根据输入,如果我一次读取一个单词,则函数调用必须与我的函数类似:
create_kid(&tree);
insert_c(tree, "BIKE");
create_kid(&tree);
insert_c(tree->kids[0], "WHEEL");
create_kid(&(tree->kids[0]));
insert_c(tree->kids[0]->kids[0], "RIM");
.
.
.
create_kid(&tree);
insert_c(tree->kids[1], "FRAME");
.
.
如果树是这样形成的,我需要从较高的深度到较低的深度,例如从NUT
到FRAME
。所以我相信一定有更简单的方法,也许是递归方法。有什么方法可以用递归实现吗?首先是琐碎的事情:
如果轴节点的同一实例位于“树”中的不同位置,则n元树不再是n元树。这是一张图表。如果你的车轴上还有一辆自行车,它甚至是一个循环图
在实现所有这些时,您会注意到差异。您将需要一个引用计数或图形中的某些内容来决定何时真正释放节点。在真正的n元树中,不需要这样做,因为每个节点在树中只出现一次
下一步的行政事项:
您决定使用指针数组作为数据结构来包含节点的子节点。因此,为了降低代码的复杂性,作为第一步,实际创建(动态)指针数组是一个好主意。优点:树代码没有动态数组代码的负担,您可以进行单元测试,甚至可以将动态指针数组重新用于其他项目
我制作了一个指针数组实现示例(它没有经过深入测试)来展示其原理
为了让这里显示的代码更加“用户友好”,首先是我使用的include,为了避免这种情况:
#include <crtdbg.h> // Windows specific - helps find memory leaks.
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
乍一看,ComponentTree\u t*tree
参数存在于ComponentTreeJoin()
中,这可能看起来有点滑稽。但是,componenttreecreatexxxnode()
函数也应该有它。为什么?因为以后很可能有人想要像ComponentTree\u t*ComponentTreeFromNode(ComponentNode\u t*node)
或ComponentNode\u t*componenttreegroot(ComponentNode\u t*node)
这样的函数
最后也是最重要的一点,树的手动组装可能是这样的(不完整,这个答案已经很长了):
总结:
- 如果它真的应该是一个图,而不是一个n元树,那么有人选择了错误的术语
- 树实现中混合的动态数组代码将降低代码的可测试性和可读性
- 如果使用动态指针数组作为子列表,或者单链接列表不是真正的基本类型。可能列表更适合,因为示例输入中的大多数节点都只有一个子,并且差异很小。数组的当前实现也没有节省堆操作的数量(但如果默认容量未编程为0,但可能为1或2或另一个合适的值,则可以)
代码显示了树是如何按照解析器遍历输入文本时产生的顺序构造的(我有时从右向左,而不是100%从左向右)main()
- 此处显示的代码并不将材料项的数量视为节点的一个成员,而是在材料名称节点的顶部生成一个编号节点。这可能但不一定是有益的,因为它完全取决于语法的定义方式和解析器的类型等。通常情况下是这样的。AST最终看起来如何ke还受解析器决策的驱动
内部,如果parent==NULL,则创建一个parent
。乍一看这是错误的。SListTreeJoin(SListTree*tree,Node*where,Node*newContent)
在我看来更好一些。尤其是当你试图解析LISP代码并将其转换为AST时。@BitTickler谢谢你的回答。是的,我的代码中有一个节点*root=NULL
。另外,我还必须添加*parent==NULL
,以防我得到根。我将尝试按照你说的那样编写函数。你有什么建议吗关于阅读/构建的建议?我不知道这也被称为AST。我只是在搜索n元树和k元树以获取信息。至少现在我有更接近的东西要找,谢谢。如果你根据一些语法解析一些文本,结果通常被称为抽象语法树(AST)。你的类似LISP的输入(不是真正的lisp,但有点类似)通常被称为SLIST树(中缀表示法中的数量值使整个内容不同于lisp)。这取决于您编写的解析器类型(自下而上或自上而下的解析器),AST通常由我上面给出的函数组成。接受的结果产生一个节点。如果在解析过程中到达输入的末尾,则顶级节点已完全构造,AST已完成。@BitTickler最后一个问题。您上面给出的函数原型应该在给定的位置插入节点,对吗?例如,如果我要将一个子节点添加到根节点,那么调用SlistTreeJoin(tree,tree->kids[0],temp)
将意味着插入?是的-如果您将一棵树与另一棵树(在顶部节点处)连接,另一棵树将作为子节点(kid)添加到何处。pseudo c
typedef struct PointerArray_tag
{
void**data;
size_t capacity;
size_t size;
} PointerArray_t;
void PointerArrayInitialize(PointerArray_t *array)
{
array->data = NULL;
array->capacity = 0;
array->size = 0;
}
int PointerArrayReserve(PointerArray_t *array, size_t capacity)
{
if (array->capacity < capacity)
{
void **newData = (void**)realloc(array->data, capacity * sizeof(void*));
if (NULL != newData)
{
array->data = newData;
array->capacity = capacity;
return 1; // 1 = "true" in C and indicates success.
}
return 0; // 0 = "false" in C and indicates failure...
}
else
{
return 1;
}
}
typedef void (*PointerArrayElementFree_t)(void *element);
int PointerArrayResize(PointerArray_t *array, size_t newSize, void* value, PointerArrayElementFree_t elementFree)
{
if (NULL == array) return 0;
if (NULL == elementFree) return 0;
if (newSize < array->size)
{
for (size_t index = newSize; index < array->size; index++)
{
elementFree(array->data[index]);
}
array->size = newSize;
return 1;
}
else if (newSize > array->size)
{
size_t oldSize = array->size;
if (PointerArrayReserve(array, newSize))
{
for (size_t index = oldSize; index < newSize; index++)
{
array->data[index] = value;
}
array->size = newSize;
return 1;
}
return 0; // Reserve() failed, so this function also failed.
}
else
return 1; // oldSize == newSize - nothing to do.
}
int PointerArrayInitializeWithCapacity(PointerArray_t *array, size_t initialCapacity)
{
PointerArrayInitialize(array);
return PointerArrayReserve(array, initialCapacity);
}
int PointerArrayPushBack(PointerArray_t *array, void*element)
{
if (PointerArrayReserve(array, array->size + 1))
{
array->data[array->size] = element;
array->size++;
return 1;
}
return 0;
}
int PointerArrayClear(PointerArray_t *array, PointerArrayElementFree_t elementFree)
{
if (NULL == elementFree) return 0;
if (NULL == array) return 0;
for (size_t index = 0; index < array->size; index++)
{
elementFree(array->data[index]);
array->data[index] = NULL;
}
array->size = 0;
return 1;
}
int PointerArrayUninitialize(PointerArray_t *array, PointerArrayElementFree_t elementFree)
{
if (PointerArrayClear(array, elementFree))
{
free(array->data);
array->data = NULL;
array->capacity = 0;
return 1;
}
return 0;
}
<Material> ::= <Count> <Name> <Size>
| <Count> <Name>
<Material> ::= <Count> <Name> <Size>
| <Count> <Name>
| <Name>
| <Name> <Size>
enum NodeContentType
{
EMPTY = 0
, NUMBER = 1
, NAME = 2
};
typedef struct NodeContent_tag
{
NodeContentType type;
union
{
float number;
char *name;
};
} NodeContent_t;
typedef struct ComponentNode_tag
{
NodeContent_t content;
ComponentNode_tag * parent;
PointerArray_t children;
} ComponentNode_t;
void ComponentNodeFree(ComponentNode_t *node)
{
// Clean up anything heap based in NodeContent_t.
switch (node->content.type)
{
case NAME:
free(node->content.name);
node->content.name = NULL;
node->content.type = EMPTY;
break;
default:
// nothing to do.
break;
}
// Free all the children below this node recursively.
PointerArrayUninitialize(&node->children, (PointerArrayElementFree_t)ComponentNodeFree);
free(node);
}
typedef struct ComponentTree_tag
{
ComponentNode_t root;
} ComponentTree_t;
void ComponentTreeInitialize(ComponentTree_t *tree)
{
tree->root.content.type = EMPTY;
PointerArrayInitialize(&tree->root.children);
tree->root.parent = NULL;
}
ComponentNode_t *ComponentTreeRoot(ComponentTree_t *tree)
{
return &tree->root;
}
void ComponentTreeClear(ComponentTree_t *tree)
{
if (NULL != tree)
{
PointerArrayClear(&tree->root.children,(PointerArrayElementFree_t)ComponentNodeFree);
}
}
void ComponentTreeUninitialize(ComponentTree_t *tree)
{
if (NULL != tree)
{
PointerArrayUninitialize(&tree->root.children, (PointerArrayElementFree_t)ComponentNodeFree);
}
}
ComponentNode_t *ComponentTreeCreateEmptyNode()
{
ComponentNode_t *node = (ComponentNode_t*)malloc(sizeof(ComponentNode_t));
if (NULL != node)
{
node->content.type = EMPTY;
node->parent = NULL;
PointerArrayInitialize(&node->children);
}
return node;
}
ComponentNode_t *ComponentTreeCreateNameNode(const char *name)
{
ComponentNode_t *node = (ComponentNode_t*)malloc(sizeof(ComponentNode_t));
if (NULL != node)
{
node->content.type = NAME;
node->content.name = _strdup(name);
assert(NULL != node->content.name);
if (NULL == node->content.name)
{
free(node);
return NULL;
}
node->parent = NULL;
PointerArrayInitialize(&node->children);
}
return node;
}
ComponentNode_t *ComponentTreeCreateNumberNode(float number)
{
ComponentNode_t *node = (ComponentNode_t*)malloc(sizeof(ComponentNode_t));
if (NULL != node)
{
node->content.type = NUMBER;
node->content.number = number;
node->parent = NULL;
PointerArrayInitialize(&node->children);
}
return node;
}
int ComponentTreeJoin(ComponentTree_t *tree, ComponentNode_t *where, ComponentNode_t *child)
{
if (NULL == child) return 0;
if (NULL != child->parent) return 0; // is already in a tree.
if (NULL == tree) return 0;
if (NULL == where)
{
where = &tree->root;
}
child->parent = where;
return PointerArrayPushBack(&where->children, child);
}
int _tmain(int argc, _TCHAR* argv[])
{
ComponentTree_t bikeTree;
ComponentTreeInitialize(&bikeTree);
ComponentNode_t * nutSize = ComponentTreeCreateNumberNode(0.15f);
ComponentNode_t * nut = ComponentTreeCreateNameNode("NUT");
ComponentTreeJoin(&bikeTree, nut, nutSize);
ComponentNode_t *nutCount = ComponentTreeCreateNumberNode(7.0f);
ComponentTreeJoin(&bikeTree, nutCount, nut);
ComponentNode_t * boltSize = ComponentTreeCreateNumberNode(0.1f);
ComponentNode_t * bolt = ComponentTreeCreateNameNode("BOLT");
ComponentTreeJoin(&bikeTree, bolt, boltSize);
ComponentNode_t * boltCount = ComponentTreeCreateNumberNode(5.0f);
ComponentTreeJoin(&bikeTree, boltCount, bolt);
ComponentNode_t * axle = ComponentTreeCreateNameNode("AXLE");
ComponentTreeJoin(&bikeTree, axle, nutCount);
ComponentTreeJoin(&bikeTree, axle, boltCount);
ComponentNode_t *axleCount = ComponentTreeCreateNumberNode(1.0f);
ComponentTreeJoin(&bikeTree, axleCount, axle);
ComponentNode_t *gearSize = ComponentTreeCreateNumberNode(25.0f);
ComponentNode_t *gear = ComponentTreeCreateNameNode("GEAR");
ComponentTreeJoin(&bikeTree, gear, gearSize);
ComponentNode_t *gearCount = ComponentTreeCreateNumberNode(2.0f);
ComponentTreeJoin(&bikeTree, gearCount, gear);
ComponentNode_t *hub = ComponentTreeCreateNameNode("HUB");
ComponentTreeJoin(&bikeTree, hub, gearCount);
ComponentTreeJoin(&bikeTree, hub, axleCount);
ComponentNode_t *hubCount = ComponentTreeCreateNumberNode(1.0f);
ComponentTreeJoin(&bikeTree, hubCount, hub);
ComponentNode_t * spokeSize = ComponentTreeCreateNumberNode(120.0f);
ComponentNode_t * spoke = ComponentTreeCreateNameNode("SPOKE");
ComponentTreeJoin(&bikeTree, spoke, spokeSize);
ComponentNode_t * spokeCount = ComponentTreeCreateNumberNode(1.0f);
ComponentTreeJoin(&bikeTree, spokeCount, spoke);
ComponentNode_t * axle1 = ComponentTreeCreateNameNode("AXLE");
ComponentNode_t * axle1Count = ComponentTreeCreateNumberNode(2.0f);
ComponentTreeJoin(&bikeTree, axle1Count, axle1);
// ...
ComponentNode_t * wheel = ComponentTreeCreateNameNode("WHEEL");
ComponentTreeJoin(&bikeTree, wheel, axle1Count);
ComponentTreeJoin(&bikeTree, wheel, spokeCount);
ComponentTreeJoin(&bikeTree, wheel, hubCount);
ComponentNode_t * wheelCount = ComponentTreeCreateNumberNode(2.0f);
ComponentTreeJoin(&bikeTree, wheelCount, wheel);
ComponentNode_t *bike = ComponentTreeCreateNameNode("BIKE");
ComponentTreeJoin(&bikeTree, bike, wheelCount);
ComponentNode_t *bikeCount = ComponentTreeCreateNumberNode(1.0f);
ComponentTreeJoin(&bikeTree, bikeCount, bike);
// .. frame branch omitted ..
ComponentTreeJoin(&bikeTree, NULL, bikeCount);
ComponentTreeUninitialize(&bikeTree);
_CrtDumpMemoryLeaks();
return 0;
}