Simple AVL tree delete is only working sometimes - c++

I'm working on an AVL tree. It seems the my remove only works correctly some of the time. I built a tree that looks like this
f
/ \
e j
/ / \
a h s
by inserting in the order f e h s j a. I know that it is working correctly on insert and balancing.
When I remove a, or j, or h, or s, or e, everything works fine. If I remove f, then it replaces f with h, which is correct, but I lose j and s.
This is the first function that is called.
void remove(const ItemType& item)
{
if(root == NULL)
return;
else
{
remove(root, item);
}
};
The first function calls this one to recursively find the correct node.
void remove(Node<ItemType>* & node, const ItemType& item)
{
if(item > node->item)
{
if (node->rightChild == NULL)
{
return; // there is nothing here to remove
}
else
{
// recurse to next node
remove(node->rightChild, item);
}
}
else if (item < node->item)
{
if (node->leftChild == NULL)
{
return; // there is nothing here to remove
}
else
{
// recurse to next node
remove(node->leftChild, item);
}
}
else if (node->item == item)
{
remove(node);
}
if (node != NULL)
node->updateHeight();
};
This is the last function to be called. This is where the deletion and swaps are done.
void remove(Node<ItemType>* & node)
{
if (node->rightChild == NULL && node->leftChild == NULL)
{
delete node;
node = NULL;
}
else if (node->rightChild == NULL)
{
Node<ItemType>* temp = node;
node = node->leftChild;
delete temp;
}
else
{
Node<ItemType>* & temp = node->rightChild;
while (temp->leftChild != NULL)
temp = temp->leftChild;
node->item = temp->item;
delete temp;
temp = NULL;
}
if(node != NULL)
node->initializeHeight();
};
I am wondering if it has something to do with the lines
Node<ItemType>* & temp = node->rightChild;
while (temp->leftChild != NULL)
temp = temp->leftChild;
node->item = temp->item;
delete temp;
temp = NULL;
and the temp pointer is acting in a behavior I am not familiar with, or if my whole implementation is wrong. I know the missing nodes are out there somewhere because my memory leak shows me those two nodes that go missing are never deleted.

I am wondering if it has something to do with the lines
Yes. Node<ItemType>* & temp = node->rightChild; says temp is an alias for node->rightChild. So the while loop modifies node->rightChild and you lose the handle to the original right child.
Take an ordinary pointer and walk it down the right subtree until you have gotten to the parent of its smallest member. Then get the value of the smallest member to copy it into node->item, and delete the parent's left child.

Related

c++ replace values in linked list by changing pointers

Having a problem with linked list. Need to create a method, which will replace data in list, by not creating a new element but by changing pointers. For now I have such method:
void replaceValues(Node* head, int indexOne, int indexTwo)
{
Node* temporaryOne = NULL;
Node* temporaryTwo = NULL;
Node* temp = NULL;
Node* current = head;
int count = 0;
while (current != NULL) {
if (count == indexOne)
{
temporaryOne = current;
}
else if (count == indexTwo)
{
temporaryTwo = current;
}
count++;
current = current->next;
}
current = head;
count = 0;
while (current != NULL) {
if (count == indexOne)
{
head = temporaryTwo;
}
else if (count == indexTwo)
{
head = temporaryOne;
}
count++;
current = current->next;
}
}
I am sure, that exists a more simpler way, how to do it, but I don't fully understand, how it works...
Thanks in advance for help.
I assume that with "replace" you actually mean "swap"/"exchange".
Some issues:
The argument head should be passed by reference, as one of the nodes to swap may actually be that head node, and then head should refer to the other node after the function has done its job.
The node before temporaryOne will need its next pointer to change, so you should stop your loops one step earlier in order to have access to that node and do that.
In some cases head may need to change, but this is certainly not always the case, so doing head = temporaryOne or head = temporaryTwo is certainly not right. In most cases you'll need to link to the swapped node from the preceding node (see previous point).
The next pointer of the node that is swapped will also need to change, as the node that follows it will be a different one than before.
As mentioned already in comments, it is advised to split the task into removals and insertions, as the fiddling with next pointers can get confusing when you try to cover all possible cases, notably making the distinction between the case where the two nodes are adjacent and when they are not.
Here are some functions that split the work into removal, insertion and finally exchanging nodes:
Node* removeNode(Node* &head, int index) {
// If index is out of range, no node is removed, and function returns nullptr
// Otherwise the extracted node is returned.
if (head == nullptr || index < 0) return nullptr;
Node* current = head;
if (index == 0) {
head = head->next;
current->next = nullptr;
return current;
}
while (--index > 0) {
current = current->next;
if (current == nullptr) return nullptr;
}
Node* temp = current->next;
if (temp != nullptr) {
current->next = temp->next;
temp->next = nullptr;
}
return temp;
}
void insertNode(Node* &head, Node* node, int index) {
// If index is too large, node is inserted at the end of the list
// If index is negative, node is inserted at the head of the list
if (index <= 0 || head == nullptr) {
node->next = head;
head = node;
return;
}
Node* current = head;
while (--index > 0 && current->next != nullptr) {
current = current->next;
}
node->next = current->next;
current->next = node;
}
bool exchangeNodes(Node* &head, int indexOne, int indexTwo)
{
// Returns true when successful, false when at least one index
// was out of range, or the two indexes were the same
if (head == NULL || head->next == NULL || indexOne == indexTwo || indexOne < 0) return false;
// To ensure the right order of operations, require the first index is the lesser:
if (indexOne > indexTwo) return exchangeNodes(head, indexTwo, indexOne);
Node* two = removeNode(head, indexTwo);
if (two == nullptr) return false; // out of range
Node* one = removeNode(head, indexOne);
insertNode(head, two, indexOne);
insertNode(head, one, indexTwo);
return true;
}

Strange Node Deletion in Binary Search Tree

I'm writing out a BST that holds some data, and I'm trying to implement the function for removing a single element from the BST.
Currently, my recursiveDelete() function looks as follows, and it works! Depending on your definition of works. It takes some other nodes along with it.
template <typename ItemType, typename KeyType>
BNode<ItemType>* BinarySearchTree<ItemType, KeyType>::recDeleteNode(KeyType key, BNode<ItemType> *subtree)
{
if (subtree == nullptr)
{
return subtree;
}
else if (subtree->getItem() > key)
{
subtree->setLeft(recDeleteNode(key, subtree->getLeft()));
}
else if (subtree->getItem() < key)
{
subtree->setRight(recDeleteNode(key, subtree->getRight()));
}
else
{
if (subtree->getLeft() == nullptr && subtree->getRight() == nullptr)
{
delete subtree;
subtree = nullptr;
}
else if (subtree->getLeft() == nullptr)
{
BNode<ItemType> *temp = subtree;
subtree = subtree->getRight();
delete temp;
}
else if (subtree->getRight() == nullptr)
{
BNode<ItemType> *temp = subtree;
subtree = subtree->getRight();
delete temp;
}
else
{
BNode<ItemType> *temp = minValueNode(subtree->getRight());
temp->setLeft(subtree->getLeft());
temp = subtree;
subtree = subtree->getRight();
delete temp;
}
}
return subtree;
}
The ItemType comparison operators are overloaded, since the key is defined inside the actual data that the Node points to.
I've been staring at this for a while, but I cannot see what would cause it to pull out another nodes along with it.
else if (subtree->getRight() == nullptr)
{
BNode<ItemType> *temp = subtree;
subtree = subtree->getRight(); // this is nullptr
delete temp;
}
That getRight should be getLeft.

Counting occurrence in singly linked list by nodes

I am writing a simple app that gets a list and saves the objects as nodes in a singly linked list and we can add(), remove(), copy(), etc. each node depending on the given data set. each node has a char value which is our data and an int count which counts the occurrence of the related char.
e.g. for a list like
a, a, b, b, c, a
there would be three nodes (since there are three different characters) which are:
[a,3,*next] -> [b,2,*next] -> [c,1,*next] -> nullptr
bool isAvailable() checks if the data is already in the list or not.
Q: When inserting a data there are two options:
The data has not been entered: so we have to create a newNodewith the given data, count=1and *next=NULL.
The data is already entered: so we have to count++ the node that has the same data.
I know if the given data is available or not, but how can I point to the node with same data?
Here's the code:
#include "stdafx.h"
#include<iostream>
using namespace std;
class Snode
{
public:
char data;
int count;
Snode *next;
Snode(char d, int c)
{
data = d;
count = c;
next = NULL;
}
};
class set
{
private:
Snode *head;
public:
set()
{
head = NULL;
tail = NULL;
}
~set();
void insert(char value);
bool isAvailable(char value);
};
set::~set()
{
Snode *t = head;
while (t != NULL)
{
head = head->next;
delete t;
}
}
bool set::isAvailable(char value)
{
Snode *floatingNode = new Snode(char d, int c);
while(floatingNode != NULL)
{
return (value == floatingNode);
floatingNode->next = floatingNode;
}
}
void set::insert(char value)
{
Snode *newNode = new Snode(char d, int c);
data = value;
if (head == NULL)
{
newNode->next = NULL;
head = newNode;
newNode->count++;
}
else
{
if(isAvailable)
{
//IDK what should i do here +_+
}
else
{
tail->next= newNode;
newNode->next = NULL;
tail = newNode;
}
}
}
I know if the given data is available or not, but how can I point to the node with same data?
You'll need to start at the head of the list and iterate along the list by following the next pointers until you find the node with the same data value. Once you've done that, you have your pointer to the node with the same data.
Some other notes for you:
bool set::isAvailable(char value)
{
Snode *floatingNode = new Snode(char d, int c);
while(floatingNode != NULL)
{
return (value == floatingNode);
floatingNode->next = floatingNode;
}
}
Why is this function allocating a new Snode? There's no reason for it to do that, just initialize the floatingNode pointer to point to head instead.
This function always returns after looking at only the first node in the linked list -- which is not the behavior you want. Instead, it should return true only if (value == floatingNode); otherwise it should stay inside the while-loop so that it can go on to look at the subsequent nodes as well. Only after it drops out of the while-loop (because floatingNode finally becomes NULL) should it return false.
If you were to modify isAvailable() slightly so that instead of returning true or false, it returned either floatingPointer or NULL, you'd have your mechanism for finding a pointer to the node with the matching data.
e.g.:
// Should return either a pointer to the Snode with data==value,
// or NULL if no such Snode is present in the list
Snode * set::getNodeWithValueOrNullIfNotFound(char value) const
{
[...]
}
void set::insert(char value)
{
Snode * theNode = getNodeWithValueOrNullIfNotFound(value);
if (theNode != NULL)
{
theNode->count++;
}
else
{
[create a new Snode and insert it]
}
}
You had a lot of problems in your code, lets see what are they:
First of all, Snode doesn't need to be a class, rather you can go with a simple strcut; since we need everything public.(not a mistake, but good practice)
You could simple initialize count = 1 and next = nullptr, so that no need of initializing them throw constructor. The only element that need to be initialized through constructor is Snod's data.
Since c++11 you can use keyword nullptr instead of NULL, which denotes the pointer literal.
Member function bool set::isAvailable(char value) will not work as you think. Here you have unnecessarily created a new Snode and cheacking whether it points to nullptr which doesn't allow you to even enter the loop. BTW what you have written in the loop also wrong. What do you mean by return (value == floatingNode); ? floatingNode is a Snode by type; not a char.
Hear is the correct implementation. Since we don't wanna overwrite the head, will create a Node* pointer and assign head to it. Then iterate through list until you find a match. If not found, we will reach the end of the isAvailable() and return false.
inline bool isAvailable(const char& value)
{
Node *findPos = head;
while(findPos != nullptr)
{
if(findPos -> data == value) return true;
else findPos = findPos->next_node;
}
return false;
}
In void set::insert(char value), your logic is correct, but implementation is wrong. Following is the correct implementation.(Hope the comments will help you to understand.
void insert(const char& value)
{
if(head == nullptr) // first case
{
Node *newNode = new Node(value);
newNode->next_node = head;
head = newNode;
}
else if(isAvailable(value)) // if node available
{
Node *temp = head;
while(temp->data != value) // find the node
temp = temp->next_node;
temp->count += 1; // and count it by 1
}
else // all new nodes
{
Node *temp = head;
while(temp->next_node != nullptr) // to find the null point (end of list)
temp = temp->next_node;
temp = temp->next_node = new Node(value); // create a node and assign there
}
}
Your destructor will not delete all what you created. It will be UB, since your are deleting newly created Snode t ( i.e, Snode *t = head;). The correct implementation is as bellow.(un-comment the debugging msg to understand.)
~set()
{
Node* temp = head;
while( temp != nullptr )
{
Node* next = temp->next_node;
//std::cout << "deleting \t" << temp->data << std::endl;
delete temp;
temp = next;
}
head = nullptr;
}
Last but not least, the naming (set) what you have here and what the code exactly doing are both different. This looks more like a simple linked list with no duplicates. This is however okay, in order to play around with pointers and list.
To make the code or iteration more efficient, you could do something like follows. In the isAvailable(), in case of value match/ if you found a node, you could simply increment its count as well. Then in insert(), you can think of, if node is not available part.
Hope this was helpful. See a DEMO
#include <iostream>
// since you wanna have all of Node in public, declare as struct
struct Node
{
char data;
int count = 1;
Node* next_node = nullptr;
Node(const char& a) // create a constrcor which will initilize data
: data(a) {} // at the time of Node creation
};
class set
{
private:
Node *head; // need only head, if it's a simple list
public:
set() :head(nullptr) {} // constructor set it to nullptr
~set()
{
Node* temp = head;
while( temp != nullptr )
{
Node* next = temp->next_node;
//std::cout << "deleting \t" << temp->data << std::endl;
delete temp;
temp = next;
}
head = nullptr;
}
inline bool isAvailable(const char& value)
{
Node *findPos = head;
while(findPos != nullptr)
{
if(findPos -> data == value) return true;
else findPos = findPos->next_node;
}
return false;
}
void insert(const char& value)
{
if(head == nullptr) // first case
{
Node *newNode = new Node(value);
newNode->next_node = head;
head = newNode;
}
else if(isAvailable(value)) // if node available
{
Node *temp = head;
while(temp->data != value) // find the node
temp = temp->next_node;
temp->count += 1; // and count it by 1
}
else // all new nodes
{
Node *temp = head;
while(temp->next_node != nullptr) // to find the null point (end of list)
temp = temp->next_node;
temp = temp->next_node = new Node(value);
}
}
void print() const // just to print
{
Node *temp = head;
while(temp != nullptr)
{
std::cout << temp->data << " " << temp->count << "\n";
temp = temp->next_node;
}
}
};
int main()
{
::set mySet;
mySet.insert('a');
mySet.insert('a');
mySet.insert('b');
mySet.insert('b');
mySet.insert('c');
mySet.insert('a');
mySet.print();
return 0;
}

Implementation of removeNode for a Binary Search Tree

I'm trying to implement a removal algorithm discussed in a textbook for a binary search tree in a program, but the book is scant on details for some of the functions described so I've guessed at their meaning and implemented the functions it specified and some of my own. The problem I'm having is with the removeNode function on handling the 0-1-2 children cases.
In the book it specifies the following pseudocode for removeNode
removeNode(N: BinaryNode)
{
if(N is a leaf)
Remove N from the tree
else if (N has only one child C)
{
if(N was a left child of its parent P)
Make C the left child of P
else
Make C the right child of P
}
else //Node has two children
{
//Find S, the node that contains N's inorder successor
//Copy the item from node S into node N
//Remove S from the tree by using the previous
//technique for a leaf or a node with one child
}
In this function, how do you make C a child of P? given a single node with nothing to point back to the parent what can you do to figure out who the parent of the tree is? Usually you need a trailing node to keep track of that but due to the books 'final draft' I suspect that wasn't what they were implying.
'Final Draft'
removeNode(nodePtr: BinaryNodePointer): BinaryNodePointer
{
if(N is a leaf)
{
//Remove leaf from the tree
delete nodePtr
nodePtr = nullPtr
return nodePtr
}
else if (N has only one child C)
{
if(N was a left child of its parent P)
nodeToConnectPtr = nodePtr->getleftChildPtr() //<---I assume this means nodePtr->left
else
nodeToConnectPtr = nodePtr->getRightChildPtr() //<--nodePtr->right?
delete nodePtr
nodePtr = nullptr
return nodeToConnectPtr
}
else //Node has two children
{
//Find the inorder succesor of the entry in N: it is in the left subtree rooted
//at N's Child
tempPtr = removeLeftMosstNode(nodePtr->getRightChild(), newNodeValue)
nodePtr->setRightChildPtr(tempPtr) //<--nodePtr->right = tempPtr?
nodePtr->setItem(newNodeValue) // nodePtr->vendorData = newNodeValue?
return nodePtr
}
This is the implementation I came up with based off the aforementioned design. I know some parts are wrong but I wasn't sure what else I could do to fix them. Could anyone suggest a fix the child cases and any other problems I might have missed?
My Implementation
aBst::treeNode * aBst::removeNode(aBst::treeNode * nodePtr)
{
//This functions deletes a node and then returns the pointer to the child to take the place of deleted child
aVendor * tempVendorPtr;
treeNode * nodeToConnectPtr, *tempPtr;
//The node passed is the node that needs to be removed
if (nodePtr->right == NULL && nodePtr->left == NULL) //----No Child----
{
delete nodePtr;
nodePtr = NULL;
return nodePtr;
}
else if ((nodePtr->right != NULL) != (nodePtr->left != NULL))//----One Child----
{
if (nodePtr->left != NULL)//left child
{
nodeToConnectPtr = nodePtr->left; //Wrong
}
else if (nodePtr->right != NULL) //right child
{
nodeToConnectPtr = nodePtr->right; //Wrong
}
delete nodePtr;
nodePtr = NULL;
return nodeToConnectPtr;
}
else //-----Two Child-----
{
//find minimum value of right subtree, stores the pointer to the vendorData it carries through the parameter and calls removeNode
tempPtr = removeLeftMostNode(nodePtr->right, tempVendorPtr);
nodePtr->vendorData = tempVendorPtr;
nodePtr->right = tempPtr;
return nodePtr;
}
}
All functions
int aBst::countKids(aBst::treeNode * subTreePtr)
{
if (subTreePtr == NULL) //Empty Tree
{
return -1;
}
else if (subTreePtr->right == NULL && subTreePtr->left == NULL) //----No Child----
{
return 0;
}
else if ((subTreePtr->right != NULL) != (subTreePtr->left != NULL))//----One Child----
{
return 1;
}
else if ((subTreePtr->right != NULL) && (subTreePtr->left != NULL))//----Two Child----
{
return 2;
}
//Something unexpected occurred
return -1;
}
bool aBst::remove(char nameOfVendor[])
{
bool failControl = false;
removeValue(root, nameOfVendor, failControl);
return failControl;
}
aBst::treeNode * aBst::removeValue(aBst::treeNode * subTreePtr, char nameOfVendor[], bool& success)
{
//Note: the subTreePtr should be root in initial call
treeNode * tmpPtr;
char name[MAX_CHAR_LENGTH];
//Make sure passed success bit is false
success = false;
subTreePtr->vendorData->getName(name);
if (subTreePtr == NULL) //Empty Tree
{
success = false;
return NULL;
}
else if (strcmp(name, nameOfVendor) == 0) //Evaluates to true if there is a match
{
subTreePtr = removeNode(subTreePtr);
success = true;
return subTreePtr;
}
else if (strcmp(name, nameOfVendor) > 0) // Go left
{
//Protects algorithm from bad data crash
if (subTreePtr->left == NULL)
{
return subTreePtr;
}
tmpPtr = removeValue(subTreePtr->left, nameOfVendor, success);
subTreePtr->left = tmpPtr;
return subTreePtr;
}
else // Go Right
{
//Protects algorithm from bad data crash
if (subTreePtr->right == NULL)
{
return subTreePtr;
}
tmpPtr = removeValue(subTreePtr->right, nameOfVendor, success);
subTreePtr->right = tmpPtr;
return subTreePtr;
}
//For loop was broken and function returns false
return subTreePtr;
}
aBst::treeNode * aBst::removeNode(aBst::treeNode * nodePtr)
{
aVendor * tempVendorPtr;
treeNode * nodeToConnectPtr, *tempPtr;
//The node passed is the node that needs to be removed
if (nodePtr->right == NULL && nodePtr->left == NULL) //----No Child----
{
delete nodePtr;
nodePtr = NULL;
return nodePtr;
}
else if ((nodePtr->right != NULL) != (nodePtr->left != NULL))//----One Child----
{
if (nodePtr->left != NULL)//left child
{
nodeToConnectPtr = nodePtr->left;
}
else if (nodePtr->right != NULL) //right child
{
nodeToConnectPtr = nodePtr->right;
}
delete nodePtr;
cout << "called\n";
nodePtr = NULL;
return nodeToConnectPtr;
}
else //-----Two Child-----
{
//find minimum value of right subtree, stores the pointer to the vendorData it carries through the parameter and calls removeNode
tempPtr = removeLeftMostNode(nodePtr->right, tempVendorPtr);
nodePtr->vendorData = tempVendorPtr;
nodePtr->right = tempPtr;
cout << "\nleaving Two Child\n";
return nodePtr;
}
}
aBst::treeNode * aBst::removeLeftMostNode(aBst::treeNode * nodePtr, aVendor*& vendorDataRef)
{
if (nodePtr->left == NULL)
{
//Target acquired
vendorDataRef = nodePtr->vendorData;
return removeNode(nodePtr);
}
else
return removeLeftMostNode(nodePtr->left, vendorDataRef);
}
I think you have a similar problem as I do. What you're doing when there is only one child, is just setting the pointer to branch to the right or left respectively. But you need to replace the node with a node from that subtree. This can be done by searching for the minimum node in the left subtree and replacing the node you wanted to remove with this minimum node. Then you need to remove the node you just inserted to prevent node duplication. That's the theory anyway. I haven't managed to implement it correctly myself.
edit: I removed the link again. I saw that it is considered bad etiquette to ask something in an answer. Shame on me /o.

How to delete a linked list without recursion?

I'm trying to find a way of deleting a linked list without recursion, because a stack overflow isn't really something nice.
I have a struct as follows:
typedef struct _my_Item
{
_my_Item(const std::string& name)
{
m_name = name;
}
~my_Item()
{
delete next; // this recursively deletes the "tail" of the list
next = NULL;
}
struct _my_Item *next;
std::string m_name;
// ... More members here...
}
In some piece of code (not relevant here) I'm constructing a list from a data file using the above structure. I keep the pointer to the head of the list in a variable and can work with it. All fine.
When I finally call the destructor on the head of the list, the destructor gets called and the delete next; causes a recursion to delete the "tail" of the list (which is the entire list without the first element). Now since the list is quite long, I see a stack overflow sometimes.
Is there a nice way to get around this problem?
~my_Item()
{
while (next)
{
_my_Item* item = next;
next = item->next;
item->next = NULL; // this prevents the recursion
delete item;
}
}
Create a class representing the list itself that will encapsulate nodes deletion in its destructor via a for/while loop. Doing it the way you do leaves the possibility to delete part of the list and leave dangling pointer.
One suggestion would be to remove the delete code from the destructor and use a pointer to delete the list.
struct _my_Item * nodeToDelete = NULL;
while(firstNode != NULL)
{
nodeToDelete = firstNode;
firstNode = firstNode->next;
delete nodeToDelete;
}
// I wrote this java code to delete a node from BST
// I only used one recursion call to remove successor
public Boolean delete(int data){
if(isEmpty() || !search(data))
return false;
return delete(null,root,data);
}
public Boolean delete(Node parent,Node temp,int data) {
while(true){
if(data == temp.getData()) {
break;
} else if(data < temp.getData()) {
parent = temp;
temp = temp.getLeft();
} else {
parent = temp;
temp = temp.getRight();
}
}
if(parent == null && (temp.getLeft() == null || temp.getRight() == null)){
if(temp.getLeft() == null)
root = temp.getRight();
else
root = temp.getLeft();
} else if(temp.getLeft() == null || temp.getRight() == null) {
if (parent.getLeft() == temp) {
if (temp.getLeft() == null)
parent.setLeft(temp.getRight());
else
parent.setLeft(temp.getLeft());
} else if (parent.getRight() == temp) {
if (temp.getLeft() == null)
parent.setRight(temp.getRight());
else
parent.setRight(temp.getLeft());
}
}else{
int min = findMin(temp.getRight());
temp.setData(min);
delete(temp,temp.getRight(),min);
}
return true;
}