Прежде всего сказать, что если вы попытаетесь решить рекурсивную проблему нерекурсивным способом, у вас возникнут проблемы.
Я видел неправильный ответ, выбранный как хороший друг, поэтому я попытаюсь показать свой подход:
Начнет с помощью ссылки указателей вместо простых указателей, так как передать ссылку корневого указателя делает его легче обнаружить (и обновить) указатели на корневой узел. Таким образом, интерфейс к подпрограмме будет следующим:
void delete_tree(struct node * * const ref);
Он представляет ссылку на указатель, указывающий на корневой узел. Я спускаюсь к узлу, и если один из child
или next
равен NULL
, то этот узел можно свободно исключить, просто указав указатель ссылки на другую ссылку (чтобы я не потерял его).Если узел имеет двух детей (child
и next
оба являются != NULL
), то я не могу удалить этот узел до тех пор, пока одна из ветвей не рухнула, а затем я выберу одну из ветвей и переместим ссылку (я объявил параметр ref
const
, чтобы обеспечить I не изменять его, поэтому я использую другие перемещение ссылки для этого)
struct node **moving_reference;
Затем алгоритм следует:
void tree_delete(struct node ** const static_ref)
{
while (*static_ref) {
struct node **moving_ref = static_ref;
while (*moving_ref) {
struct node *to_be_deleted = NULL;
if ((*moving_ref)->child && (*moving_ref)->next) {
/* we have both children, we cannot delete until
* ulterior pass. Just move the reference. */
moving_ref = &(*moving_ref)->child;
} else if ((*moving_ref)->child) {
/* not both != NULL and child != NULL,
* so next == NULL */
to_be_deleted = *moving_ref;
*moving_ref = to_be_deleted->child;
} else {
/* not both != NULL and child == NULL,
* so follow next */
to_be_deleted = *moving_ref;
*moving_ref = to_be_deleted->next;
} /* if, else if */
/* now, delete the unlinked node, if available */
if (to_be_deleted) node_delete(to_be_deleted);
} /* while (*moving_ref) */
} /* while (*static_ref) */
} /* delete_tree */
Я включил этот алгоритм в полном примере, s как вы парциальные деревья и положение moving_ref
, когда оно движется по дереву. Он также показывает проходы, необходимые для его удаления.
#include <stdio.h>
#include <stdlib.h>
#define N 100
#define D(x) __FILE__":%d:%s: " x, __LINE__, __func__
#define ASSERT(x) do { \
int res; \
printf(D("ASSERT: (" #x ") ==> %s\n"), \
(res = (int)(x)) ? "TRUE" : "FALSE"); \
if (!res) exit(EXIT_FAILURE); \
} while (0)
struct node {
int key;
struct node *child;
struct node *next;
}; /* struct node */
struct node *node_alloc(void);
void node_delete(struct node *n);
/* This routine has been written recursively to show the simplicity
* of traversing the tree when you can use recursive algorithms. */
void tree_traverse(struct node *n, struct node *p, int lvl)
{
while(n) {
printf(D("%*s[%d]\n"), lvl<<2, p && p == n ? ">" : "", n->key);
tree_traverse(n->child, p, lvl+1);
n = n->next;
} /* while */
} /* tree_traverse */
void tree_delete(struct node ** const static_ref)
{
int pass;
printf(D("BEGIN\n"));
for (pass = 1; *static_ref; pass++) {
struct node **moving_ref = static_ref;
printf(D("Pass #%d: Considering node %d:\n"),
pass, (*moving_ref)->key);
while (*moving_ref) {
struct node *to_be_deleted = NULL;
/* print the tree before deciding what to do. */
tree_traverse(*static_ref, *moving_ref, 0);
if ((*moving_ref)->child && (*moving_ref)->next) {
printf(D("Cannot remove, Node [%d] has both children, "
"skip to 'child'\n"),
(*moving_ref)->key);
/* we have both children, we cannot delete until
* ulterior pass. Just move the reference. */
moving_ref = &(*moving_ref)->child;
} else if ((*moving_ref)->child) {
/* not both != NULL and child != NULL,
* so next == NULL */
to_be_deleted = *moving_ref;
printf(D("Deleting [%d], link through 'child' pointer\n"),
to_be_deleted->key);
*moving_ref = to_be_deleted->child;
} else {
/* not both != NULL and child != NULL,
* so follow next */
to_be_deleted = *moving_ref;
printf(D("Deleting [%d], link through 'next' pointer\n"),
to_be_deleted->key);
*moving_ref = to_be_deleted->next;
} /* if, else if */
/* now, delete the unlinked node, if available */
if (to_be_deleted) node_delete(to_be_deleted);
} /* while (*moving_ref) */
printf(D("Pass #%d end.\n"), pass);
} /* for */
printf(D("END.\n"));
} /* delete_tree */
struct node heap[N] = {0};
size_t allocated = 0;
size_t deleted = 0;
/* simple allocation/free routines, normally use malloc(3). */
struct node *node_alloc()
{
return heap + allocated++;
} /* node_alloc */
void node_delete(struct node *n)
{
if (n->key == -1) {
fprintf(stderr,
D("doubly freed node %ld\n"),
(n - heap));
}
n->key = -1;
n->child = n->next = NULL;
deleted++;
} /* node_delete */
/* main simulation program. */
int main()
{
size_t i;
printf(D("Allocating %d nodes...\n"), N);
for (i = 0; i < N; i++) {
struct node *n;
n = node_alloc(); /* the node */
n->key = i;
n->next = NULL;
n->child = NULL;
printf(D("Node %d"), n->key);
if (i) { /* when we have more than one node */
/* get a parent for it. */
struct node *p = heap + (rand() % i);
printf(", parent %d", p->key);
/* insert as a child of the parent */
n->next = p->child;
p->child = n;
} /* if */
printf("\n");
} /* for */
struct node *root = heap;
ASSERT(allocated == N);
ASSERT(deleted == 0);
printf(D("Complete tree:\n"));
tree_traverse(root, NULL, 0);
tree_delete(&root);
ASSERT(allocated == N);
ASSERT(deleted == N);
} /* main */
Пожалуйста, разместите определение структуры 'Node'. Ваш код в настоящее время неполный и не может быть четко интерпретирован. – Transcendental
@Transcendental Я добавил его – andre
проверить этот код на гораздо меньшее количество узлов - например, 1, 2, 3 - возможно, этого будет достаточно, чтобы увидеть причину ... – PiotrNycz