2015-12-09 3 views
0

Я пытаюсь написать деструктор для моего двоичного дерева поиска, и я знаю, как рекурсивно прокручивать дерево, но я не знаю, как это сделать в деструкторе, чтобы каждый узел был удален.Деструктор для дерева двоичного поиска

Мой Заголовок является:

struct Node; 
typedef string TreeType; 
typedef Node * TreePtr; 

//Defines a Node 
struct Node 
{ 
    TreeType Info; 
    int countDuplicates = 1; 
    TreePtr Left, Right; 
}; 

class Tree 
{ 
public: 
    //Constructor 
    Tree(); 

    //Destructor 
    ~Tree(); 

    //Retruns true if the tree is Empty 
    bool Empty(); 

    //Inserts a Node into the tree 
    bool Insert(TreeType); 

    //Delete decides what type of delection needs to occur, then calls the correct Delete function 
    bool Delete(Node * , Node *); 

    //Deletes a leaf node from the tree 
    bool DeleteLeaf(TreePtr, TreePtr); 

    //Deletes a two child node from the tree 
    bool DeleteTwoChild(TreePtr); 

    //Deletes a one child node from the tree 
    bool DeleteOneChild(TreePtr, TreePtr); 

    //Finds a certain node in the tree 
    bool Find(TreeType); 

    //Calculates the height of the tree 
    int Height(TreePtr); 

    //Keeps a count of the nodes currently in the tree; 
    void Counter(); 

private: 

    //Prints the nodes to the output text file in order alphabetically 
    void InOrder(ofstream &,TreePtr); 

    //Defines a TreePtr called Root 
    TreePtr Root; 

    //Defines a TreePtr called Current 
    TreePtr Current; 

    //Defines a TreePtr called Parent 
    TreePtr Parent; 
}; 

Мой конструктор:

Tree::Tree() 
{ 
    Root = NULL; 
    Current = NULL; 
    Parent = NULL; 
} 

Есть ли способ вызвать деструктор рекурсивно? Если нет, как мне пройти через каждый узел, чтобы удалить его.

+0

Представьте себе, если вы могли бы вызвать деструктор рекурсивно. Деструктор работает с текущим объектом, являющимся «Деревом», а не «Узлом». И он не принимает никаких параметров. Итак, как он узнает, какой узел разрушить? – immibis

ответ

2
void Tree::DestroyRecursive(TreePtr node) 
{ 
    if (node) 
    { 
     DestroyRecursive(node->left); 
     DestroyRecursive(node->right); 
     delete node; 
    } 
} 

Tree::~Tree() 
{ 
    DestroyRecursive(Root); 
} 
+0

Я сделал это, и я получил эту ошибку: «Начал сборку: Проект: BinarySearchTree, Конфигурация: Отладка Win32 ------ BST.cpp BST.obj: ошибка LNK2019: неразрешенный внешний символ« public: void __thiscall Tree :: DestroyRecursive (struct Node *) "(? DestroyRecursive @ Tree @@ QAEXPAUNode @@@ Z), на который ссылается функция« public: __thiscall Tree :: ~ Tree (void) »(?? 1Tree @@ QAE @ XZ) C: \ Пользователи \ Matthew \ Desktop \ Comp245 \ BinarySearchTree \ Debug \ BinarySearchTree.exe: фатальная ошибка LNK1120: 1 неразрешенные внешние ========== Build: 0 удался, 1 не удалось, 0 обновлено, 0 пропущено ========== " –

+0

Я понял это. Я забыл «Дерево ::» в функции void. Благодарю. @JohnZwinck –

+0

@MatthewDanielSorrell: Я действительно не имел в виду, что 'DestroyRecursive' является членом' Tree'. Вы можете сделать это таким образом, если хотите, но он также может быть обычной бесплатной функцией. –

1

Вам нужно два деструкторов:

Tree::~Tree() 
{ 
    delete Root; 
} 

и

Node::~Node() 
{ 
    delete Left; 
    delete Right; 
} 

Но вы на самом деле не нужны два класса здесь. Каждый Node - это дерево.

+0

Это затрудняет работу с деревом, например, удаление одного узла, не так ли? Потому что он делает редукцию каждого узла. –

+0

@JohnZwinck Нет, вы просто настраиваете узел и его окружающие узлы перед его удалением. Например, если вы удаляете сам узел, а не его дочерние элементы, вы присоедините его левое и правое поддеревья к другим узлам, очистите их в самом узле, а затем удалите узел. – EJP

+0

Да, это справедливо. Если есть такая сильная концепция владения, то, возможно, умные указатели будут лучше с самого начала. –

0

При вызове delete или ваш Tree идет до конца жизни (выход из блока, как пример в конце), вы должны delete в Tree детях Node с и оператор delete будет вызывать деструктор, смотрите пример в конце.

Это приведет к тому, что Дерево полностью исчезнет из памяти при вызове дрессировщика дерева.

Просто попробуйте это:

#include <iostream> 
using namespace std; 

class Node { 
    Node *left, *right; 
public: 
    Node(Node *l, Node *r); 
    ~Node(); 
}; 

class Tree { 
    Node *root; 
public: 
    Tree(Node *rt); 
    ~Tree(); 
}; 

Tree::Tree(Node *rt):root(rt) { 
    cout << "new Tree with root node at " << rt << endl; 
} 
Tree::~Tree() { 
    cout << "Destructor of Tree" << endl; 
    if (root) delete root; 
} 
Node::Node(Node *l, Node *r):left(l), right(r) { 
    cout << "[email protected]" 
     << this 
     << "(left:" << l 
     << ", right:" << r << ")" 
     << endl; 
} 
Node::~Node() { 
    cout << "[email protected]" << this 
     << endl; 
    if (left) delete left; 
    if (right) delete right; 
} 

int main() { 
    Tree t(
     new Node(
      new Node(
       new Node(
        new Node(0, 0), 
        0), 
       0), 
      new Node(0, new Node(0, 0)))); 
} 
+0

Это функционально ничем не отличается от предыдущего ответа EJP. –

+0

, но он работает, даже если узел имеет нулевые указатели !!! Основная разница заключается в том, что этот ответ проверяется, а @ ejp - нет. Он показывает последовательность вызовов деструктора и то, как дерево создается и удаляется. Кроме того, он позволяет находить «Дерево» в стеке (как показано). –

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