I have to implement a binary search tree using C++ for one of assignments. I've created the class, and attempted to implement the InsertItem, PrintTree, DeleteTree methods for the class, I think I did everything right but for some reason my program keeps crashing :(
Here's my code:
PrintTree Method
template <class TItem>
void BinarySearchTree<TItem>::PrintTree()
{
PrintTree(RootNode);
}
template <class TItem>
void BinarySearchTree<TItem>::PrintTree(BinarySearchTreeNode* Node)
{
if(Node == NULL)
return;
cout << Node->Data << endl;
PrintTree(Node->LeftChild);
PrintTree(Node->RightChild);
}
DeleteTree Method
template <class TItem>
void BinarySearchTree<TItem>::DeleteTree()
{
DeleteTree(RootNode);
}
template <class TItem>
void BinarySearchTree<TItem>::DeleteTree(BinarySearchTreeNode* Node)
{
if(Node == NULL)
return;
DeleteTree(Node->LeftChild);
DeleteTree(Node->RightChild);
delete Node;
}
My sequence of method calls up until the program crashes:
I insert items F,B,G,A,D,I,C,E,H: works fine
I call PrintTree(): works fine
I call DeleteTree(): works fine
I call PrintTree() again: program crashes
For some reason the expression if(RootNode == NULL) is not returning true after the DeleteTree() method is called, so the program tries to print something that doesn't exist and crashes. I'm not sure why this is happening, what am I doing wrong here?
Any and all help is appreciated.
Calling "delete" does not null out the pointer.
You will want to do:
delete Node;
Node = nullptr;
EDIT:
Pass the pointer by address so that you can clean up dangling pointers as you go:
void BinarySearchTree<TItem>::DeleteTree(BinarySearchTreeNode *&node);
I think the delete function should be changed to the following,
template <class TItem>
void BinarySearchTree<TItem>::DeleteTree(BinarySearchTreeNode** Node)
{
if((*Node) == NULL)
return;
DeleteTree(&(*Node)->LeftChild);
DeleteTree(&(*Node)->RightChild);
delete (*Node);
(*Node) = NULL;
}
Please correct me if I am wrong.
Related
I have an AVL tree (I will not post all of the code because it wouldn't make sense), and I want to use a recursive function to delete it. The code looks something like this:
template <typename T>
struct AVL
{
Nod<T>* root;
....
void clear();
....
};
template<typename T>
inline void AVL<T>::clear()
{
....
if (root == nullptr)
{
return;
}
clear(root->left); //I can't do this because clear doesn't take parameters
clear(root->right);
....
}
In order to delete my nodes I want to recursively call this function, without taking parameters, it has to start from the root inside that struct everytime. But if I define the function without having parameters, I won't be able to call clear(root->left).
So, my question is:
how can I recursively call this function starting from the root field?
You can change it from clear(root->left) to root->left->clear() and the same with right node but you need to check whether they are nullptr before call clear
Create another private function that takes parameters:
template<typename T>
void AVL<T>::clear_helper(Node<T>* node)
{
clear_helper(node->left);
clear_helper(node->right);
....
}
template<typename T>
inline void AVL<T>::clear()
{
....
if (root == nullptr)
{
return;
}
clear_helper(root);
}
I'm trying to write my own code for the erase function used in dynamic structures (lists specifically) of the stl library for a school project
What I had in mind was to do a loop until i found the node prior to the one i wanted to delete.
while (loop->next!= NULL){
if (loop->next==pValue){
break;
}
else {
loop->next;
}
}
prev=loop;
delete loop;
Then I want to update its pointer and instead of having it point to the node to be deleted, i want it to point to the node after the one i'm going to delete.
So can i do this?
*(prev->next)=*(pValue->next);
in case i can't, what should i do?
Here's my function erase
template <class T>
void list<T>::erase(pos pValue){
list<T>::pos prev;
list<T>::pos temp=pValue->next;
list<T>::pos loop=list<T>::first();
while (loop->next!= NULL){
if (loop->next==pValue){
break;
}
else {
loop->next;
}
}
prev=loop;
delete loop;
*(prev->next)=*(pValue->next);
delete list<T>::get(pValue);
}
And here's part of my class list
template <class T>
class list {
node<T> *pFirst;
int n;
public:
typedef node<T> *pos;
void erase(pos pValue);
};
And the structure of the node:
template <class T>
class node {
public:
T info;
node<T> *next;
};
I have a one-dimensional template list that contains nodes, each node has a link to next node.
It works rather well on it's own, but not when it contains another linked list.
LinkedList and Node looks something like that:
template <class T>
class LinkedList
{
private:
Node<T>* pPreHead;
public:
LinkedList(void);
~LinkedList(void);
Node<T>* getHead(void);
int size();
void addElementToEnd(T& value);
void deleteNextNode(Node<T>* pNodeBefore);
}
template <class T>
class Node
{
private:
T value;
Node* next;
public:
Node();
Node* getNext();
Node* getValue();
void setNext(Node* nextElem);
void setValue(T elem);
};
Now for the task I need to use LinkedList>, which is filled via a loop.
It looks something like this:
ifstream fl;
fl.open("test1.in", std::ifstream::in);
while (fl.good())
{
string currentLine;
getline(fl, currentLine);
LinkedList<string> newDNA;
//newDNA being filled here so I skipped code
DNAStorage.addElementToEnd(newDNA);
//Place 1
}
//Place 2
Now if I insert some test output code in "Place 1" everything is fine, but when the loop enters new iteration newDNA variable gets freed and so is the pointer inside DNAStorage (which is LinkedList<LinkedList<string>> in question), and when I try to print anything in "Place 2" I get segmentation fault.
Unfortunately I can't use any other data structures since this is the kind of task I need to do.
My question is - how can this be fixed, so that it actually is not freed prematurely?
Edit:
Here's my code for AddElementToEnd(T& value):
template <class T>
void LinkedList<T>::addElementToEnd(T &value)
{
Node<T> *newtail = new Node<T>;
newtail.setNext(NULL);
newtail.setValue(value);
if(pPreHead == NULL)
{
pPreHead = newtail;
return;
}
Node<T> *tail = pPreHead;
while(tail.getNext() != NULL)
{
tail = tail.getNext();
}
tail.setNext(newtail);
}
The problem is that you are storing references to objects that are going out of scope, causing undefined behavior when you try and access them. Your LinkedList<string> newDNA gets created and destroyed with each iteration of the while loop, yet you pass a reference to be stored in DNAStorage list.
One solution would be to store a copy of each object (not reference) in the list when addElementToEnd() gets called.
I'm having a problem entirely deleting my AVL tree. I've figured out how to delete just a single node, but my destroyTree function doesn't seem to actually destroy every node recursively. What could I be doing wrong?
I have a struct nodeType<myType>
template <class myType>
struct nodeType {
myType keyValue;
int nodeHeight;
nodeType<myType> *left;
nodeType<myType> *right;
};
and I am attempted to delete all existing nodes with:
if(node != NULL) {
destroyTree(node->left);
destroyTree(node->right);
delete node;
}
node = NULL;
but this does not seem to properly delete the nodes, when checking for the height it still gives me the height before the destroy was called although crashes when attempting to print. In the main function calling destroy tree I used a simple if statement
template <class myType>
void avlTree<myType>::destroyTree()
{
destroyTree(root);
if(root == NULL)
std::cout << "destroyed" << std::endl;
}
shows that root is NOT null (yes is not printed)
Look at this piece of code:
destroyTree(root);
if(root == NULL)
std::cout << "destroyed" << std::endl;
Probably your destroyTree function has this prototype:
void destroyTree(nodeType<myType> *node);
The problem is that node cant update the caller memory address, but only the contents that caller is pointing. This means that root will never be update, i.e., its contents cant be updated to NULL.
To do that, you need a prototype that is something like that:
void destroyTree(nodeType<myType> **node);
I'm guessing you're not taking node by reference, and therefore when you set the node to NULL you're actually setting a local copy of the node to null.
Won't work because root is taken by value - will have prior value after function call:
template <class myType>
void avlTree<myType>::destroyTree(nodeType<myType>* node) // note node taken by value here
{
if(node != NULL) {
destroyTree(node->left);
destroyTree(node->right);
delete node;
}
node = NULL;
}
Will work because root is taken by reference - will be null after the function call:
template <class myType>
void avlTree<myType>::destroyTree(nodeType<myType>* &node) // note node taken by reference here
{
if(node != NULL) {
destroyTree(node->left);
destroyTree(node->right);
delete node;
}
node = NULL;
}
I am making a tree of n children to store directories of computer. Now, concept is simply make a tree (that would not be a BT of course) and each node will have children as well. Consider the code below then I will explain the problem.
First Consider this:
C/users/DeadCoder/Movies/Batman.
Now In my main.cpp I have this all C, users, DeadCoder, Movies, Batman in a vector and then I send two pairs in insert Func. if root==NULL; it would just insert C. Next time C and users would go. It would find C and then insert users occordingly. Let's now see the code .
template <class T>
struct Node;
template <class T>
class tree
{
Node<T> *root;
public:
tree();
~tree();
int insert(T str, T str1);
Node<T> *getRoot();
Node<T> *search(T item, Node<T> *tempPtr);
};
template <class T>
struct Node{
T n;
Node<T> *sibling;
tree<T> children; // SEE my each node has children.
Node(T N){
this->n = N;
this->sibling = NULL;
}
};
// In .cpp FILE;
// Initilaizer
template <class T>
tree<T>::tree() // Constructor Initialization.
{
root=NULL;
}
// Insert Function.
template <class T>
int tree<T>::insert(T push, T find)
{
Node<T> *rPtr = root;
if (rPtr==NULL){
//ROOT is NULL. C needs to be inserted which is in find.
Node<T> *pusPtr = new Node<T>(find);
root = pushPtr;
root->sibling=NULL;
return 0;
}
else if(rPtr!=NULL){
Node<T> *pushPtr = new Node<T>(push);
Node<T> *temp2 = search(find, root);
Node<T> *temp = temp2->children.getRoot(); // say it LINE_40.
if (temp==NULL){
temp = pushPtr;
temp->sibling=NULL;
return 1;
}
// children are already present.
else if(temp!=NULL){
// You don't need to know code for this part.
}
}//if.
}
// Search Function.
template <class T>
Node<T> *tree<T>::search(T data, treeNode<T>* N)
{
if (N->n==data){ // where n represent directory.
return N; // data found.
}//if....
else{
Node<T> *child = N->children.getRoot();
// This is where i get Segmentation fault,
// because child is ==NULL; but you see in LINE_40 I did insert the child for C.
if(child!=NULL){ // say it line 80.
search(data, child);
}//if...
if(child->sibling!=NULL){
search(data, child->sibling);
}
}
}// search....
PROBLEM: C inserted. Users inserted. Now in search function at Line 80, it comes to find the child for C. and it should be Users as I have inserted it in LINE 40. BUT Instead it says child==NULL. I have been debugging for hours and I don't know why it says so. I hope Everybody gets the problem.
Now I really need to know why it is regarding C child to be NULL, It has to be users. Can anyOne see what is the problem???? HELP !!!!
Line 42 does nothing (I mean it has no side effect). It just puts a value in a temporary variable then leaves.
You probably want your temp to be a reference to the root. Something like: Node<T> *&temp =
Are you sure insert method actually inserted these elements?
It might be helpful to implement postconditions so to verify your methods actually fulfill their contract (design by contract).
This way you'll directly get what is wrong and debugging will be fast or unnecessary in some cases, since you'll get log messages saying "this method was supposed to do this but failed doing it", otherwise you'll look for hours where the problems comes from.