简体   繁体   中英

Recursively clearing a binary tree not working even though I set the individual nodes to NULL & delete them

I was trying to create a binary tree structure in cpp using the coderunner IDE on MacOS. I was supposed to have two separate files called bintree.h and bintree.cpp but I couldn't make that work due to some linker error which I couldn't fix. So I just combined both files into binarytree.h and created a client file main.cpp. The code compiles & runs successfully. However, upon checking the output, everything seems to be working except the tree_clear() function. Even after clearing the tree I can still print the cleared tree using the print() function even though I set the cleared nodes to NULL and then deleted them. Why is this happening? I'm at a dead end. Please help. Thanks in advance.

The following is my code of file binarytree.h

#ifndef BINARYTREE_H
#define BINARYTREE_H

#include <cstdlib>  // Provides NULL and size_t
#include <iostream>
#include <iomanip>

using namespace std;

class binary_tree_node 
{

public:

// TYPEDEF
typedef int value_type;

// CONSTRUCTOR with definition
binary_tree_node(const int& init_data = int(), binary_tree_node* init_left = NULL, binary_tree_node* init_right = NULL)
{ 
    data_field = init_data; 
    left_field = init_left; 
    right_field = init_right;
}

// MODIFICATION MEMBER FUNCTIONS
int &data( ) { return data_field; }
binary_tree_node* left( ) { return left_field; }
binary_tree_node* right( ) { return right_field; }
void set_data(const int &new_data) { data_field = new_data; }
void set_left(binary_tree_node* new_left) { left_field = new_left; }
void set_right(binary_tree_node* new_right) { right_field = new_right; }


// CONST MEMBER FUNCTIONS
const int& data( ) const { return data_field; }
const binary_tree_node* left( ) const { return left_field; }
const binary_tree_node* right( ) const { return right_field; }
bool is_leaf( ) const 
    { return (left_field == NULL) && (right_field == NULL); }

private:

int data_field;
binary_tree_node *left_field;
binary_tree_node *right_field;
};
#endif



////////////////////////////////////////////
////////////////////////////////////////////
// IMPLEMENTATION CODE /////////////////////
// bintree.cpp         /////////////////////
////////////////////////////////////////////
////////////////////////////////////////////
// I had to combine files bintree.h and  ///
// bintree.cpp into one file called      ///
// binarytree.h as in Mac OS the linker  ///
// generates an error during compilation ///
////////////////////////////////////////////
////////////////////////////////////////////

void print(binary_tree_node *node_ptr, int depth) 
{
    if (node_ptr != NULL) 
    {
        print(node_ptr->right( ), depth+1);
        std::cout << std::setw(4*depth) << ""; // Indent 4*depth spaces.
        std::cout << node_ptr->data( ) << std::endl;
        print(node_ptr->left( ),  depth+1);
    }
}

void tree_clear(binary_tree_node *root_ptr) 
{
    if (root_ptr != NULL) 
    {
        tree_clear( root_ptr->left( ) );
        tree_clear( root_ptr->right( ) );
        root_ptr = NULL;
        delete root_ptr;
    } 
}

//  void tree_clear(binary_tree_node *root_ptr) 
//  {
//      if (root_ptr == NULL) { return; }
//      tree_clear(root_ptr->left());
//      tree_clear(root_ptr->right());
//      root_ptr = NULL;
//      delete root_ptr;
//  }


binary_tree_node* tree_copy(const binary_tree_node* root_ptr)
{
    // Library facilities used: cstdlib
    binary_tree_node *l_ptr;
    binary_tree_node *r_ptr;

    if (root_ptr == NULL) return NULL;
    else
    {
        l_ptr = tree_copy( root_ptr->left( ) );
        r_ptr = tree_copy( root_ptr->right( ) );
        
        return
        new binary_tree_node( root_ptr->data( ), l_ptr, r_ptr);
    }
} 

The following is the main.cpp

#include <iostream>
#include "binarytree.h"

using namespace std;

int main(int argc, char *argv[]) 
{
//Constructor usage
binary_tree_node leftLeaf1(1), rightLeaf1(7), leftNode1(84, &leftLeaf1, NULL), rightNode1(120, NULL, &rightLeaf1), rootNode1(100, &leftNode1, &rightNode1);
cout << "Printing tree after creation through constructor:\n";
print(&rootNode1, 3);
//cout << "Print line address " << &rootNode1 << endl;

// Copying the tree
binary_tree_node* treeCopyRoot = tree_copy(&rootNode1);
cout << "\nPrinting treeCopyRoot after using tree_copy() to copy rootNode1:\n";
print(treeCopyRoot, 2);

//cout << "\nValue in root " << rootNode1.data();
//cout << "\nPrinting rootNode1:\n";


// Clearing the tree
tree_clear(&rootNode1);
cout << "\nPrinting tree after clearing through tree_clear:\n";
print(&rootNode1, 3);

}

I see now. You have created the binary_tree_node objects in main on the stack. The memory locations held by those objects is bound to the main function. They will get released only when main function ends.

You see when tree_clear is called, the address, &root_node1 gets copied into pointer root_ptr . This when assigned to NULL , loses access to the address &root_node1 hence delete virtually does nothing as it frees memory from address location NULL . If you first try to do delete root_ptr , it gives you the error you mentioned in the comments because of reason I mentioned above.

To fix this, allocate memory on heap (use new to create binary_tree_node objects in main ). That way the memory is not bound to anything and you can delete this memory from any function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM