Following is my code to recursively delete every nodes in a Binary Search Tree:
template <class T>
bool BST<T>::clear()
{
if(root == NULL)
{
cout << "Empty" << endl;
return false;
}
else
{
clearNodes(root);
return true;
}
}
template <class T>
void BST<T>::clearNodes(BTNode<T> *cur)
{
if(cur == NULL)
{
return;
}
clearNodes(cur->left);
clearNodes(cur->right);
delete cur;
}
In my main function, when I try to print out the content to check whether the nodes are deleted after running my clear function, somehow I encounter the weird display here:
May I know that is my nodes are actually deleted through the clear function above?
Thanks for your guides!
I assume "checking that the nodes are deleted" is equivalent to clear() printing empty. Your algorithm is missing the step where it reset the deleted node.
A modified version is
template <class T>
void BST<T>::clearNodes(BTNode<T>* &cur) //reference on pointer
{
if (cur==NULL)
{
return;
}
clearNodes(cur->left);
clearNodes(cur->right);
delete cur;
cur = NULL; //neccessary
}
Edit : Explanation about changes
Once you observe the issue about the node not set to null, the first iteration will be to set the node in question after every call, ie
clearNodes(cur->right);
cur->right = NULL;
This give the responsibility to the caller, and his a potential defect because sooner or later the caller may forget to set to null or may set the wrong value. Thus you want to set in clearNodes.In order to modify a pointer inside the function you need to pass either a pointer to it or a reference. In c++, I prefer to pass a reference. Thus the signature become¨
void BST<T>::clearNodes(BTNode<T>* &cur);
I guess that the root of the tree is not set to Null, therefor it holds garbage, and the print function is iterating a random-garbage tree.
Make sure you set NULL to the tree root when the clear method ends.
template <class T>
bool BST<T>::clear()
{
if (root==NULL)
{
cout << "Empty" << endl;
return false;
}
else
{
clearNodes(root);
root = NULL;
return true;
}
}
I assume that when you print - you check if the tree root is null or not in order to determine whether the tree is empty or not.
Related
Why is it just pushing last element??? I have made the last element nullptr so the leaf above that should become the last node right? Why is not working
void ans(TreeNode* root)
{
if(root->left!=nullptr)
{
ans(root->left);
if(root->left==nullptr)
{
cout<<"fdfef";
}
}
if(root->right!=nullptr)
{
ans(root->right);
}
if(root->left==nullptr&&root->right==nullptr)
{
cout<<root->val;;
q.push_back(root->val);
root=nullptr;
return;
}
}
... so the leaf above that should become the last node right?
No, root is a local, separate variable, and assigning to that variable does not affect that pointer that was passed by value.
The solution is to pass by reference:
void ans(TreeNode* &root)
// ^^
I was testing a recursive function that frees the memory of a linked list. I attempted to print the list's contents after deleting it to ensure that it had been deleted, but it doesn't seem to be possible to test if a node has been deleted since the pointer still exists. I get the same errors while using a simpler function to delete the list as well. Unless I'm making a mistake somewhere my question is:
Is there a way to test for deleted nodes?
My delete function:
template <typename node>
void deleteList(node root) {
if (!root) {
return;
}
deleteList(root->next);
delete root;
}
My print list function:
template <typename node>
void printList(node root) {
node current = NULL;
if (root) {
current = root;
cout << "if (root) == true\n";
cout << "root is: " << root << "\n";
}
while (current) {
cout << current->in << "\n";
current = current->next;
}
}
If I call printList(node) after I've called deleteList(node), printList evaluates if (root) to true as well as while (current), so cout << current->in ends up causing a segmentation fault.
When you free memory it is good practice to set the pointer to it to null (nullptr in modern C++). This makes it easier to test if that memory is freed later. It is part of defensive programming.
This will cause your (!root) check to fail on freed memory. This is a practice you should follow for all dynamically allocated memory so that you do not try and use an invalid pointer. Much better to crash due to a null pointer than to have code that seems to work but is actually corrupted.
delete doesn't set the pointer to nullptr, you have to do that manually:
template <typename node>
void deleteList(node& root) {
// ^
if (!root) {
return;
}
deleteList(root->next);
delete root;
root = nullptr; // <<<<<<<<<<<
}
I'm working on an assignment and there's a problem I'm stuck on. So I'm making a doubly linked list. I want a a delete function that will take item as argument, search for that argument in the list. when it has found the node which contains that item, I have to DELETE that node. I am aware of how I would change the previous and next pointers to the the nodes around that node. The problem that has been bugging me however, is that when I just change the next pointer of the node before it and the previous pointer of the node after it, like in the code below, the particular node will only be disconnected from the list but it will still remain in the freestore. How do I delete it from there so that the memory it is taking is also freed?
The following is the code I have. Please take a look:
template <class T>
void LinkedList<T>::deleteElement(T item)
{
ListItem<T> *curPtr;
curPtr = searchFor(item); // this function returns the pointer to the node which contains the item.
(curPtr->next)->prev = curPtr->prev;
(curPtr->prev)->next = tempPtr->next;
}
So you see, the curPtr is being disconnected, but I believe it still exists somewhere on the freestore. How do I get rid of it permanantly?
Could you make an erase_next() method for your ListItem type?
I have something like the following in a similar class. Hope it helps.
void erase_next() {
// ensure it is not the last item
if(this->next != nullptr) {
// create a temporary pointer
ListItem<T>* tmp = this->next
// link next to the next item to the next item and change the
// next items previous item to this item
this->next = this->next->next;
next->prev = this;
// delete the old next item
delete tmp;
}
}
In your function you could call it with something like the following. Thanks to #davmac edits have been made to delete the first item
template <class T>
void LinkedList<T>::deleteElement(T item)
{
ListItem<T> *curPtr = searchFor(item);
if(curPtr->prev == nullptr) {
curPtr->next->prev = nullptr;
delete curPtr;
} else {
curPtr->prev->erase_next()
}
}
Edit:
I played around with this again, and you should be able to optimize the erase_next() function with the following
void erase_next() {
if(this->next != nullptr) {
this->next = this->next->next
// We've already linked next so we can delete the handle
// with prev Note: this method is not possible with a
// single linked list and we would need the temp variable
delete this->next->prev
next->prev = this;
}
}
That way you don't have to declare a temp variable.
I am writing a method to Delete duplicate-value nodes from a sorted linked list in c++. I'm trying to use Node* instead of void return type but facing an error because of the return statement.
My method code..
Node* RemoveDuplicates(Node *head)
{
struct Node* current = head;
struct Node* next_next;
if(current == NULL)
return;
while(current->next != NULL)
{
if(current->data == current->next->data)
{
next_next = current->next->next;
free(current->next);
current->next = next_next;
}
else
{
current = current->next;
}
}
}
The compile time error message i am receiving..
solution.cc: In function 'Node* RemoveDuplicates(Node*)':
solution.cc:31:6: error: return-statement with no value, in function returning 'Node*' [-fpermissive]
return ;
^
Change the return type to void.
There is nothing valuable to be returned from the function.
The compiler doesn't pretend to know what you are thinking, he asks you to make contracts on what is going on. Hence, declaring the return type Node* you must provide an output of that specific type : a Node pointer. The most likely scenario I can imagine here would be returning the current node without the duplicates at the end of the function.
Node* RemoveDuplicates(Node *head)
{
// some instructions
return head;
}
so you can have this kind of semantic :
Node* distinctList = RemoveDuplicates(head);
if (distinctList) // NULL (0 / false) if empty
{
// some more instructions
}
However, if you don't need anything to go out of the function, the return type should be void (nothing).
Hope this helps!
I will treat this as a learning exercise, and ignore the fact that it is preferable to use a std list than to implement your own linked list, and it is preferable to use new and delete to using malloc and free.
If you specify Node* as a return type, you must return a pointer to a node. In order to answer your question, you have to ask is: what pointer do you want to return? As written you are deleting all duplicate pointers. Do you want to return the last pointer deleted? Do you want to loop until you find a duplicate and delete that?
You have two exit points in your code snippet. The first is a plain "return" statement, which is called when the list is empty. As written you are returning void, i.e. nothing. You need to return a pointer to a Node, but you have no valid pointers, so you probably want to return a null_ptr, which is a pointer to nothing.
Now we come to the part of your question which depends on the desired behavior. For example:
while(current->next != NULL)
{
if(current->data == current->next->data)
{
next_next = current->next->next;
free(current->next);
current->next = next_next;
/// Here you have a valid pointer you could return:
return current;
}
else
{
current = current->next;
}
// if you get here, no duplicates were found, so you can return a nullptr.
return std::nullptr;
}
Will loop over your list until a duplicate is found, will delete that duplicate, and return a pointer to the remaining pointer. If no duplicates are found, a nullptr is returned.
I leave it as an exersize to modify this to loop over all elements in the list until the last duplicate is found (hint, you will have to introduce a local variable to store the return value), and return that.
Good luck.
I'm a beginner programmer(Just started) and I'm writing some code for a binary search tree for fun.
For some reason, whenever I call this append function my program crashes. It has to do with one of the two functions itself, not anything else in the header file or my source file which includes main(). By the way Leaf is just a struct with an int value, and two Leaf pointers named left and right.
This crashes with no output error.
Leaf* BinarySearchTree::GetLeaf(int x,Leaf*a)
{
int key = a->value;
cout <<key<<"\n";
if(x > key)
{
if(a->right == NULL)
{
Leaf* newleaf = new Leaf();
newleaf->value = x;
a->right = newleaf;
return newleaf;
}
else if (a->right != NULL)
{
return a->right;
}
}
else if(x< key)
{
if(a->left == NULL)
{
Leaf* newleaf = new Leaf();
newleaf->value = x;
a->left = newleaf;
return newleaf;
}
else if (a->left != NULL)
{
return a->left;
}
}
else if(x == key)
{
//tbc
}
}
void BinarySearchTree::Append(int x)
{
if(root != NULL)
{
Leaf* current = root;
while(current->value != x)
{
current = BinarySearchTree::GetLeaf(x,current);
cout<<"value: "<<
current->value;
}
}
else
{
cout <<" No ROOT!";return;
}
}
If you want to see my main (source) file, go here(Since I don't want to flood this post)
http://pastebin.com/vrh7KkMm
If you want to see the rest of the header file, where these two functions are located,
http://pastebin.com/ZGWewPdV
In your BinarySearchTree constuctor, you start accessing root without having allocated memory for it first. This may be your crash. Try adding
root = new Leaf()
at the start of the constructor.
Edit - More information:
C++ does not automatically set values for your member variables, you normally need to initialize them by hand. (c++11 does allow you to do it in the declaration). This means that any variable that you don't set to a value will have a garbage value in it. If you use this garbage value as a pointer, you will most likely get a crash.
In your case, one of the initial problems is that the LinkedList class did not initialize its root member variable in the constructor before starting to reference it.
BinarySearchTree has the same problem.
Learning to use the debugger is one of the best things you can do when learning to program. It lets you step through your code one line at a time and look at the value of each variable. This makes i easy to see where things aren't going as you planned. Which debugger you use depends on your platform.
If GetLeaf() is called with x == key the function returns neither nullptr nor a valid pointer. This is a potential crash source. You need to return something sensible in any case.
UPDATE: Don't forget to initialize the Leaf structure properly in its constructor (all three members).
UPDATE2: Also initialize your root properly. I would initialize it with nullptr and change the append function in a way that it creates the very first leave if root==nullptr.