2017-02-20 3 views
1

Я реализовал функцию, которая удаляет узел дерева вместе с его поддеревьев, как это:C Бесконечный цикл после удаления двоичного дерева

void DeleteTree(BTreeNode * bt){ 
    if(bt == NULL) 
     return; 

    DeleteTree(bt->left); 
    DeleteTree(bt->right); 

    printf("del tree data: %d \n", bt->data); 
    free(bt); 
} 

А то у меня есть еще одна функция, которая просматривает дерево:

void PreorderTraverse(BTreeNode * bt, VisitFuncPtr action){ 
    if(bt == NULL) 
     return; 

    action(bt->data); 
    PreorderTraverse(bt->left, action); 
    PreorderTraverse(bt->right, action); 
} 

Здесь параметр «действие» является указателем на функцию, который принимает данные узла как аргумент и имеет тип возвращаемого типа, используемый для вызова другой функции, которая печатает данные, которые имеет узел.

Вот моя главная:

#include <stdio.h> 
#include <stdlib.h> 
#include "BinaryTree.h" 

void ShowIntData(int data){ 
    printf("%d ", data); 
} 

int main(){ 
    BTreeNode * bt1 = MakeBTreeNode(); 
    BTreeNode * bt2 = MakeBTreeNode(); 
    BTreeNode * bt3 = MakeBTreeNode(); 
    BTreeNode * bt4 = MakeBTreeNode(); 
    BTreeNode * bt5 = MakeBTreeNode(); 
    BTreeNode * bt6 = MakeBTreeNode(); 

    SetData(bt1, 1); 
    SetData(bt2, 2); 
    SetData(bt3, 3); 
    SetData(bt4, 4); 
    SetData(bt5, 5); 
    SetData(bt6, 6); 

    MakeLeftSubTree(bt1, bt2); 
    MakeRightSubTree(bt1, bt3); 
    MakeLeftSubTree(bt2, bt4); 
    MakeRightSubTree(bt2, bt5); 
    MakeRightSubTree(bt3, bt6); 

    PreorderTraverse(bt1, ShowIntData); 
    printf("\n"); 
    DeleteTree(bt3); 
    PreorderTraverse(bt1, ShowIntData); 

    return 0; 
} 

Проблема заключается в том, после того, как DeleteTree, когда PreorderTraverse вызывается снова, программа попадает в бесконечный цикл, печатая некоторые значения для мусора. Не могли бы вы объяснить, почему это происходит? Для вашей справки, я покажу вам BinaryTree.h и BinaryTree.c ниже для вашей справки.

BinaryTree.h

#ifndef __BINARY_TREE_H__ 
#define __BINARY_TREE_H__ 

typedef int BTData; 

typedef struct _bTreeNode{ 
    BTData data; 
    struct _bTreeNode * left; 
    struct _bTreeNode * right; 
} BTreeNode; 

BTreeNode * MakeBTreeNode(void); 
BTData GetData(BTreeNode * bt); 
void SetData(BTreeNode * bt, BTData data); 

BTreeNode * GetLeftSubTree(BTreeNode * bt); 
BTreeNode * GetRightSubTree(BTreeNode * bt); 

void MakeLeftSubTree(BTreeNode * main, BTreeNode * sub); 
void MakeRightSubTree(BTreeNode * main, BTreeNode * sub); 

typedef void VisitFuncPtr(BTData data); 

void PreorderTraverse(BTreeNode * bt, VisitFuncPtr action); 
void InorderTraverse(BTreeNode * bt, VisitFuncPtr action); 
void PostorderTraverse(BTreeNode * bt, VisitFuncPtr action); 

void DeleteTree(BTreeNode * bt); 

#endif // __BINARY_TREE_H__ 

BinaryTree.c

#include <stdio.h> 
#include <stdlib.h> 
#include "BinaryTree.h" 

BTreeNode * MakeBTreeNode(void){ 
    BTreeNode * nd = (BTreeNode*)malloc(sizeof(BTreeNode)); 

    nd->left = NULL; 
    nd->right = NULL; 
    return nd; 
} 

BTData GetData(BTreeNode * bt){ 
    return bt->data; 
} 

void SetData(BTreeNode * bt, BTData data){ 
    bt->data = data; 
} 

BTreeNode * GetLeftSubTree(BTreeNode * bt){ 
    return bt->left; 
} 

BTreeNode * GetRightSubTree(BTreeNode * bt){ 
    return bt->right; 
} 

void MakeLeftSubTree(BTreeNode * main, BTreeNode * sub){ 
    if(main->left != NULL) 
     free(main->left); 

    main->left = sub; 
} 

void MakeRightSubTree(BTreeNode * main, BTreeNode * sub){ 
    if(main->right != NULL) 
     (main->right); 

    main->right = sub; 
} 

void PreorderTraverse(BTreeNode * bt, VisitFuncPtr action){ 
    if(bt == NULL) 
     return; 

    action(bt->data); 
    PreorderTraverse(bt->left, action); 
    PreorderTraverse(bt->right, action); 
} 

void DeleteTree(BTreeNode * bt){ 
    if(bt == NULL) 
     return; 

    DeleteTree(bt->left); 
    DeleteTree(bt->right); 

    printf("del tree data: %d \n", bt->data); 
    free(bt); 
} 

Большое спасибо.

+0

Время, чтобы узнать, как использовать отладчик .... – LPs

+0

Я использовал отладчик, и он говорит, что ошибка происходит в функции ShowIntData, но если память для узла дерева освобождена, не следует, чтобы параметр bt в PreorderTraverse был равен NULL и ушел из f соборование? – Ned

+0

См. Мой ответ. free не устанавливает переданный указатель на «NULL» автоматически. Вы должны увидеть его с помощью отладчика. – LPs

ответ

3

free не устанавливается пройден указатель на NULL.

Вызов PreorderTraverse после удаления вызывает Undefined Behavior, потому что функция попытается разыменовать освобожденную динамическую память.

+0

Вот почему ... Большое спасибо! Тогда, если я хочу установить переданный указатель на NULL, мне нужно сделать это вручную после free() ;? – Ned

+0

Да, вы должны сделать это вручную. – LPs

+2

@Ned Это будет намного сложнее, чем это. Указателем, которому нужно установить значение null, является дочерний указатель в * родительском * узле (указатель на правый указатель bt1). Указатель 'bt3' не имеет никакого отношения к вашему фактическому дереву, кроме первоначально указывающего на узел, который вы вставили в него. Честно говоря, что вы все еще это делаете, это плохая идея. Как только в дереве, доступ должен быть через указатель * дерева * ссылки. Я * сильно * советую вам познакомиться с использованием указателей для указателей. Невозможно написать правильный код управления деревьями на C, не делая этого. – WhozCraig

0

линия номер 38 на вашем BinaryTree.c (функция MakeRightSubTree) должна быть

free(main->right);

вместо

(main->right);

+0

Извините, я мог бы испортить это, пока я копировал и вставлял ... – Ned

Смежные вопросы