I would like to ask for corrections on that function. The problem is that it deletes more nodes than there are leaves. Means it is deleting all the leaves first, and then it is deleting the just created leaves.
Please, advise me how to correct it.
Leaf = node without children nodes.
typedef struct node {
int key;
node* left;
node* right;
}node;
void BST::DeleteLeafs()
{
if (root == nullptr)
throw InvalidOperationException();
else
deleteLeavesHelper(nullptr, root);
}
void BST::deleteLeavesHelper(node* parent, node* n)
{
if (n == nullptr)
return;
else
{
if (n->left == nullptr && n->right == nullptr)
{
n = nullptr;
if (parent != nullptr)
{
parent->left = nullptr;
parent->right = nullptr;
}
}
else
{
deleteLeavesHelper(n, n->left);
deleteLeavesHelper(n, n->right);
}
}
}
You write:
if (n->left == nullptr && n->right == nullptr)
{
n = nullptr;
if (parent != nullptr)
{
parent->left = nullptr;
parent->right = nullptr;
}
}
One problem, you should deallocate the memory for n, otherwise you have a memory leak. n=nullptr; is completely useless.
Another problem, you nullify pointers to both children of parent. Instead, you need to nullify only the pointer to the correct child:
if (n->left == nullptr && n->right == nullptr) {
if (parent != nullptr) {
if (parent->left == n)
parent->left = nullptr;
else if (parent->right == n)
arent->right = nullptr;
else
// raise some exception
}
// deallocate n
}
Related
debug result
Attached my code for trying to delete a node in bst.
If I want to delete node 1, when specifying tmp = del in "if (del_node->l_ == NULL)", and remove tmp, then del is removed as well, and the tree data is lost. how can I solve this issue?
Example tree:
3
/ \
1 5
\
2
all data members and functions are declared public for simplicity.
void BST::DeleteNode(int data) {
BinaryTreeNode* &del_node = BST_Search(head_, data);
if (!del_node->l_ && !del_node->r_)
{
delete del_node;
del_node = nullptr;
return;
}
if (del_node->l_ == NULL)
{
BinaryTreeNode* tmp = del_node;
del_node = del_node->r_;
tmp = nullptr;
delete tmp;
return;
}
if (del_node->r_ == NULL)
{
BinaryTreeNode* tmp = del_node;
del_node = del_node->l_;
delete tmp;
return;
}
else
{
del_node->data_ = smallestRightSubTree(del_node->r_);
}
}
int BST::smallestRightSubTree(BinaryTreeNode* rightroot)
{
// if rightroot has no more left childs
if (rightroot && !rightroot->l_)
{
int tmpVal = rightroot->data_;
BinaryTreeNode* tmp = rightroot;
rightroot = rightroot->r_;
delete tmp;
return tmpVal;
}
return smallestRightSubTree(rightroot->l_);
}
int main()
{
BST bst;
bst.BST_Insert(bst.head_, 3);
bst.BST_Insert(bst.head_, 5);
bst.BST_Insert(bst.head_, 1);
bst.BST_Insert(bst.head_, 2);
bst.DeleteNode(1);
return 0;
}
Thanks for help!
EDIT: this is how tmp and del_node look like after the line "del_node = del_node->r_)" in the condition "if(del->l = null)"
void BST::BST_Insert(BinaryTreeNode*& head, int data) {
if (head == nullptr) {
head = new BinaryTreeNode(data, nullptr, nullptr);
return;
}
if (data > head->data_) {
BST_Insert(head->r_, data);
}
else {
BST_Insert(head->l_, data);
}
}
BinaryTreeNode* BST::BST_Search(BinaryTreeNode* root, int key) {
if (root == nullptr || root->data_ == key)
return root;
if (key > root->data_)
return BST_Search(root->r_, key);
return BST_Search(root->l_, key);
}
If your BST_Search returns a BinaryTreeNode* by value, what is the reference in BinaryTreeNode* &del_node = BST_Search(head_, data); actually referencing? It allocates a new temporary and references that. You probably wanted it to reference the variable that is holding the pointer in the tree so that you can modify the tree.
Your BST_Search would have to look like this:
BinaryTreeNode*& BST::BST_Search(BinaryTreeNode*& root, int key) {
if (root == nullptr || root->data_ == key)
return root;
if (key > root->data_)
return BST_Search(root->r_, key);
return BST_Search(root->l_, key);
}
I can't check whether this actually works, because you didn't provide a self-contained compilable example. But something along these lines.
I'm running valgrind on a program, and while the program executes just fine, valgrind reports this:
==6542== Invalid read of size 4
==6542== at 0x8049C6F: Table::removeWebsite(Table&) (Table.cpp:146)
==6542== by 0x8049768: main (app.cpp:140)
==6542== Address 0x43f87d4 is 4 bytes inside a block of size 8 free'd
==6542== at 0x402B528: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-x86-linux.so)
==6542== by 0x8049BB0: Table::removeWebsite(Table&) (Table.cpp:124)
==6542== by 0x8049768: main (app.cpp:140)
I'm not entirely sure what is wrong. Here is the code that valgrind is pointing to...
bool Table::removeWebsite(Table& parm)
{
bool flag = false; //flag to show if an item is removed or not
int OriTableSize = currCapacity;
for (int index = 0; index < OriTableSize; index++) //search through array list, starting at index
{
Node *current = parm.aTable[index];
Node *prev = nullptr;
while (current != nullptr) //search through linked lists at array[index]
{
if (current->data->getRating() == 1) //search ratings for 1
{
if (prev == nullptr) //if current is the start of the list
{
if (current->next == nullptr) //if current is the only item in this list
{
delete current;
size--;
parm.aTable[index] = nullptr;
flag = true;
}
else
{
parm.aTable[index] = current->next; //point to the next item in list
delete current;
size--;
flag = true;
}
}
else //reset prev->next pointer to skip current
{
prev->next = current->next;
delete current;
size--;
flag = true;
}
}
prev = current;
current = current->next; //go to next position in linked list
}
}
if (flag == true)//at least one item was removed
return true;
else
return false;
}
That "delete current" points to a Node, which has:
struct Node
{
Node(const SavedWebsites& parm)
{
data = new SavedWebsites(parm);
next = nullptr;
};
~Node()
{
delete data;
next = nullptr;
}
SavedWebsites *data;
Node *next;
};
and the data in SavedWebsites has the destructor:
//Default Destructor
SavedWebsites::~SavedWebsites()
{
if (this->topic)
{
delete [] this->topic;
this->topic = nullptr;
}
if (this->website)
{
delete [] this->website;
this->website = nullptr;
}
if (this->summary)
{
delete [] this->summary;
this->summary = nullptr;
}
if (this->review)
{
delete [] this->review;
this->review = nullptr;
}
rating = 0;
}
*note the items "topic" "website" "summary" and "review" are all created with
... = new char[strlen(topic)+1] //(We have to use Cstrings)
I'm fairly new to all of this, so any ideas of what may be causing this valgrind invalid read?
You did not indicate which line corresponds to Table.cpp:146, but based on the Valgrind output, it looks like the allocation in question represents a Node instance because the size of 8 bytes matches (assuming a 32-bit system). The invalid read is triggered by the offset 4 of that instance and a size of 4, so this must correspond to the member next.
Table.cpp:146:
current = current->next; //go to next position in linked list
In case of a delete in the iteration, you access the deleted node current afterwards. You also initialize prev based on the invalid pointer, so the next pointer of the last valid node will not be updated correctly in case of deletes.
Your code seems to work fine (but is not) because its behavior depends on the allocator in use and other allocations. If the allocator were to fill the freed memory with a pattern or if that memory was reused immediately and written to, you'd see a segmentation fault.
To address this issue, I'd defer the delete. Before the next iteration, you can then either read the next node and delete the original current or update prev and read the next node.
bool del = false;
if (current->data->getRating() == 1) //search ratings for 1
{
if (prev == nullptr) //if current is the start of the list
{
if (current->next == nullptr) //if current is the only item in this list
{
parm.aTable[index] = nullptr;
}
else
{
parm.aTable[index] = current->next; //point to the next item in list
}
del = true;
flag = true;
}
else //reset prev->next pointer to skip current
{
prev->next = current->next;
del = true
flag = true;
}
}
if (del)
{
Node *deletenode = current;
current = current->next;
delete deletenode;
size--;
}
else
{
prev = current;
current = current->next; //go to next position in linked list
}
package LinkList2;
//import java.util.*;
public class Duplicates {
public static void removeDuplicates(LinkedListNode head)
{
LinkedListNode current = head;
while(current!= null && current.next!= null)
{
LinkedListNode curr = current;
while(curr!=null)
{
if(curr.next.data==current.data) //Getting error at this line
curr.next = curr.next.next;
else
curr = curr.next;
}
current = current.next;
}
}
public static void main(String args[])
{
LinkedListNode first = new LinkedListNode(0,null,null);
LinkedListNode head = first;
LinkedListNode second = first;
for(int i=1; i< 8; i++)
{
second = new LinkedListNode(i%2, null, null);
first.setNext(second);
second.setPrevious(first);
}
System.out.println(head.printForward());
removeDuplicates(head);// Getting error at this line
}
}
Getting null pointer exception in the above code. When I try to run the above code, it gives null pointer exception.
Please help me with my mistake.
Below is the implementation of LinkList where all the methods are defined
class LinkedListNode {
public LinkedListNode next;
public LinkedListNode prev;
public LinkedListNode last;
public int data;
public LinkedListNode(int d, LinkedListNode n, LinkedListNode p) {
data = d;
setNext(n);
setPrevious(p);
}
public void setNext(LinkedListNode n) {
next = n;
if (this == last) {
last = n;
}
if (n != null && n.prev != this) {
n.setPrevious(this);
}
}
public void setPrevious(LinkedListNode p) {
prev = p;
if (p != null && p.next != this) {
p.setNext(this);
}
}
public String printForward() {
if (next != null) {
return data + "->" + next.printForward();
} else {
return ((Integer) data).toString();
}
}
public LinkedListNode clone() {
LinkedListNode next2 = null;
if (next != null) {
next2 = next.clone();
}
LinkedListNode head2 = new LinkedListNode(data, next2, null);
return head2;
}
}
You are getting an exception just because of the following condition:
while(curr != null)
Replace it with while(curr != null && curr.next != null) this way you can check if you have the next element.
Hope this helps.
The problem is that here:
while(curr != null)
{
if(curr.next.data==current.data) //Getting error at this line
curr.next = curr.next.next;
else
curr = curr.next;
}
You are accessing the curr.next.data where you are not checking if that node is null or not. This through your NullPointerException.
To fix your problem is to check on the while loop, if the .next is also not null.
while(curr != null && curr.next != null)
{
if(curr.next.data==current.data) //Getting error at this line
curr.next = curr.next.next;
else
curr = curr.next;
}
In other words, you are not checking if your next node is actually the end of the linked list (i.e null). If you need in your program logic to handle this separately, then you should remove the check from the while loop, and implement this check differently.
I am trying to implement a removeLast function for a linked list in objective-c. My add function property works well because I can see the node I created, but when I try to remove a node it does not work. I have tried looking up general solutions for this, but have not come up with anything. Is there something special with objective-c that I should take a look at?
-(void) removeLast{
Node *newNode = [[Node alloc]init];
Node *tail = [[Node alloc]init];
if (self.head == NULL){
NSLog(#"No items to remove");
}
else{
newNode = self.head;
tail= self.head;
while (tail != NULL) {
tail = tail.next;
if (tail != NULL){
newNode = tail;
}
}
newNode.next = NULL;
}
}
I believe you've overcomplicated the algorithm. You don't need to keep a reference to the previous link if you always look one step ahead:
- (void) removeLast {
if (self.head == NULL) {
NSLog(#"Empty list");
} else if (self.head.next == NULL) {
self.head = NULL;
} else {
Node* current = self.head;
while (current.next.next != NULL)
current = current.next;
current.next = NULL;
}
}
This iterates through until it reaches the next-to-last node when current.next.next will be null. Then it makes that the last node.
This is not an homework. I am just totally blocked on this. I know what to do but I am having difficulty manipulating the tree. please help.
I am trying to delete and node from an BST. I am able to lookup and find the parent and store it an tree.
package com.test.binarytree;
public class BinaryTreeDelete {
private Node root;
//create null binary tree
public BinaryTreeDelete(){
root = null;
}
//delete
public void delete(int target){
root = delete(root, target);
}
public Node delete(Node node, int target){
NodeWithParent temp = lookupFindParent(root, null, target);
if( node == null){
return null;
}
else{
if( node.left == null || node.right == null) //leaf node
{
//WHAT DO I DO HERE
//temp.parent.left = null;
//temp.parent.right = null;
//return null;
}
if( node.left != null && node.right == null ) //one child only on left
{
//WHAT DO I DO HERE
}
if( node.right != null && node.left == null ) //one child only on right
{
//WHAT DO I DO HERE
}
if( node.left != null && node.right != null ) //two children
{
//WHAT DO I DO HERE
}
}
return null;
}
private NodeWithParent lookupFindParent(Node node, Node parentNode, int target){
if( node == null ){
return null;
}
if( node.data == target){
return new NodeWithParent(node, parentNode);
}
else if( node.data > target ){
parentNode = node;
return lookupFindParent(node.left, parentNode, target);
}
else{
parentNode = node;
return lookupFindParent(node.right, parentNode, target);
}
}
//insert
public void insert(int data){
root = insert(root, data);
}
public Node insert (Node node, int data){
if(node == null){
node = new Node(data);
}
else{
if( data <= node.data ){
node.left = insert(node.left, data);
}
else{
node.right = insert(node.right, data);
}
}
return node;
}
//print tree
public void printTree(){
printTree(root);
System.out.println();
}
//print tree
private void printTree(Node node) {
if (node == null) return;
// left, node itself, right
printTree(node.left);
System.out.print(node.data + " ");
printTree(node.right);
}
//node class
public static class Node{
Node left;
Node right;
int data;
Node(int newNode){
data = newNode;
left = null;
right = null;
}
}
//node class
public static class NodeWithParent{
Node current;
Node parent;
NodeWithParent(Node current, Node parent){
this.current = current;
this.parent = parent;
}
}
public static void main(String[] args) {
BinaryTreeDelete bt = new BinaryTreeDelete();
//insert with inserts - tree increases on right if inserted in order
bt = new BinaryTreeDelete();
bt.insert(5);
bt.insert(3);
bt.insert(7);
bt.insert(1);
bt.insert(4);
bt.insert(6);
bt.insert(9);
bt.printTree();
//bt.delete(3);
//bt.delete(4);
//bt.delete(6);
bt.delete(9);
//bt.delete(5);
bt.printTree();
}
}
I'm going to provide you the logic (that means you have to write the code yourself) of how to delete a node in a BST.
There are three cases.
Node to be deleted has both left and right child as null: Delete the node and make the parent point to null.
Node to be deleted has either left or right child (but not both) as null: Delete the node but make sure that the parent points to the valid child of the to-be-deleted node.
Node to be deleted has nether left child nor right child as null: In this case, you have to find the next greater element of the to-be-deleted node. This next greater element is the least element of the right subtree of the to-be-deleted node. Since this is the least element, it has at least one of its child as null. So swap the values of the to-be-deleted node with the next greater node. After you swap, delete this next greater node using points 1 and 2 (whichever is fitting to the situation). Now, why the next greater node and not any node. Because if you replace a node with its next greater node, the BST remains a BST. Try it out in an example and it will be clear.