树的每个节点可能有任意数量的子节点。我需要一种构建和遍历这样的树的方法,但要使用一维向量或列表来实现。
树的每个节点可能有任意数量的子节点。我需要一种构建和遍历这样的树的方法,但要使用一维向量或列表来实现。
A
| \
B E ___
|\ \ \ \
C D F G H
你的向量看起来会像这样:
idx: 0 1 2 3 4 5 6 7
nodes: A B C D E F G H
next: _ 4 3 _ _ 6 7 _
其中_
是空指针。
编辑:
另一种方法:
对于该方法给定的树将如下所示:
idx: 0 1 2 3 4 5 6 7 8 9 A B
nodex: A _ B E _ C D _ F G H _
child: 2 5 8 _ _ _ _ _
这样你就可以轻松地找到任意给定节点的子节点,并重新组织数组,而不必移动所有元素(只需将子节点复制到表格末尾,更新指针并将下一个子节点添加到表格末尾)
你基本上要做的是编写一个内存管理器的开端,通过将向量的元素成对配对到 cons 单元中来实现 Lisp 解释器。这是我刚刚用 C 拼凑出来的东西:
#include <stdbool.h>
#include <iso646.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#define MEMORY_SIZE 1024
#define NIL 0
#define IVAL_MASK 0x8000000
struct pair
{
bool allocated;
size_t first;
size_t second;
};
size_t allocate_pair(struct pair vector[])
{
for (size_t i = 1; i < MEMORY_SIZE; i++)
{
if (not vector[i].allocated)
{
vector[i].allocated = true;
return i;
}
}
return NIL;
}
size_t make_pair(struct pair vector[], size_t a, size_t b)
{
size_t the_pair = allocate_pair(vector);
if (the_pair != NIL)
{
vector[the_pair].first = a;
vector[the_pair].second = b;
return the_pair;
}
else
{
fprintf(stderr,
"Out of pairs -- make_pair(%p, %zu, %zu)",
vector,
a,
b);
exit(EXIT_FAILURE);
}
}
size_t first(struct pair vector[], size_t index)
{
assert(vector[index].allocated);
return vector[index].first;
}
size_t second(struct pair vector[], size_t index)
{
assert(vector[index].allocated);
return vector[index].second;
}
void print_pair_aux(struct pair[], size_t, size_t);
void print_pair(struct pair vector[], size_t p)
{
assert(vector[p].allocated);
size_t a = first(vector, p);
size_t b = second(vector, p);
printf("(");
print_pair_aux(vector, a, b);
printf(")");
}
void print_pair_aux(struct pair vector[], size_t a, size_t b)
{
if (a == NIL)
printf("NIL");
else if (a >= IVAL_MASK)
printf("%zu", a &~ IVAL_MASK);
else
print_pair(vector, a);
if (b == NIL)
printf("");
else if (b >= IVAL_MASK)
printf(" . %zu", b &~ IVAL_MASK);
else
{
printf(" ");
print_pair_aux(vector,
first(vector, b),
second(vector, b));
}
}
int main(void)
{
struct pair *vector = calloc(MEMORY_SIZE, sizeof *vector);
#define cons(A,B) make_pair(vector, (A), (B))
#define ival(x) ((x) | IVAL_MASK)
size_t a = cons(ival(3), cons(ival(4), NIL));
size_t b = cons(ival(2), cons(a, NIL));
size_t c = cons(ival(6), cons(ival(7), cons(ival(8), NIL)));
size_t d = cons(ival(5), cons(c, NIL));
size_t e = cons(ival(1), cons(b, cons(d, NIL)));
print_pair(vector, e);
puts("");
}
$ cc -std=c99 try.c $ ./a.out (1 (2 (3 4)) (5 (6 7 8)))以上内容与编程有关。
你可以使用一维链表来实现它,开销很小。
每个父节点都包含指向其子节点的指针。(但这需要事先确定节点的最大数量)。
对于以A为根节点,B、C、D为子节点的树,其表示如下。
A -> B A -> C A -> D
请注意,从A有3个链接。
克服节点数量上限的一种方法是在节点中添加额外的指针。
因此,现在A ->(child) B ->(adj) ->(adj) C ->(adj) -> D。
在删除发生时更新树相当复杂。
如果您能告诉各种操作的时间界限,那么设计更好的数据结构甚至更容易。
如果节点的值没有限制,并且假设您只能使用单个列表,我会按以下方式构建它:
将每个节点表示为(val; [int; ...])
,其中val是节点的值,每个int是其子节点在列表中的位置。如有必要,可以使用不可打印的分隔符。
遍历速度非常慢。