This is a code to delete a node from a Binary Search Tree:
My question is: Why do we pass the node pointer by reference to DelSingle function but we only pass a node pointer to DelDoubleByCopying function?
template <class T>
bool BST<T>::DeleteNode(T& val)
{
BSTNode<T> * node = root, *prev = NULL;
if (IsEmpty() == true)
return false;
while (node != NULL)
{
if (node->val == val)
break;
prev = node;
if (val < node->val)
node = node->left;
else
node = node->right;
}
if (node == NULL)
return false;
if (node->left == NULL || node->right == NULL)
{
if (node == root)
DelSingle(root);
else if(node == prev->left)
DelSingle(prev->left);
else
DelSingle(prev->right);
}
else
DelDoubleByCopying(node);
return true;
}
template <class T>
void BST<T>::DelSingle(BSTNode<T>*& ptr)
{
BSTNode<T>* delNode = ptr;
if(delNode->left == NULL) // node does not have a left child
ptr = delNode->right;
else if(delNode->right == NULL) // node does not have a right child
ptr = delNode->left;
delete delNode;
}
template <class T>
void BST<T>::DelDoubleByCopying(BSTNode<T>* node)
{
BSTNode<T> *prev, *rep;
rep = node->left; //Find the largest child in the left subtree
prev = node;
while (rep->right != NULL)
{
prev = rep;
rep = rep->right;
}
node->val = rep->val;
if (prev == node)
prev->left = rep->left;
else
prev->right = rep->left;
delete rep;
}
And this is the class of Binary Search Tree node:
template <class T>
class BSTNode
{
public:
BSTNode(T& val, BSTNode* left, BSTNode* right);
~BSTNode();
T GetVal();
BSTNode* GetLeft();
BSTNode* GetRight();
private:
T val;
BSTNode* left;
BSTNode* right;
int depth, height;
friend class BST<T>;
};
DelSingle()
Given the follwing structure
parent
ptr1 ptr2
child1
And sssuming we are deleting ptr1:
Basically, what DelSingle() does is to swap child1 with ptr1 and then get ride of child1 (child1 is not what ptr1 once was).
ptr is passed by reference because you are actually changing the pointer, parent's left child is not child1.
DelDoubleByCopying()
You don't need to pass node by reference because node is not going to change, the one who changes is node->left (or node->right).
Related
This class's purpose is to emulate the functions of a Binary Search Tree. In the below code, I am trying to adapt it from a struct and a bunch of functions, into a wrapper class, called BST. One thing I am not sure of however, is how to access 'root' from within the node struct. Root is currently declared within the BST class.
class bst
{
public:
struct Node
{
public:
int data;
struct Node *left;
struct Node *right;
Node* FindMin(Node* root)
{
while(root->left != NULL) root = root->left;
return root;
}
Node* Insert(Node *root,int data)
{
if(root == NULL) {
root = new Node();
root->data = data;
root->left = root->right = NULL;
//Update Height & Size
bstHeight = 0;
bstSize = 0;
}
else if(data <= root->data)
root->left = Insert(root->left,data);
else
root->right = Insert(root->right,data);
return root;
}
Node* Delete(struct Node *root, int data)
{
if(root == NULL) return root;
else if(data < root->data) root->left = Delete(root->left,data);
else if (data > root->data) root->right = Delete(root->right,data);
//Value found
else {
// Case 1: No child
if(root->left == NULL && root->right == NULL)
{
delete root;
root = NULL;
//Update Height & Size
bstHeight = 0;
bstSize = 0;
}
//Case 2: One child
else if(root->left == NULL)
{
struct Node *temp = root;
root = root->right;
delete temp;
//Update Height & Size
bstHeight = 0;
bstSize = 0;
}
else if(root->right == NULL)
{
struct Node *temp = root;
root = root->left;
delete temp;
//Update Height & Size
bstHeight = 0;
bstSize = 0;
}
// case 3: 2 children
else
{
struct Node *temp = FindMin(root->right);
root->data = temp->data;
root->right = Delete(root->right,temp->data);
//Update Height & Size
bstHeight = 0;
bstSize = 0;
}
}
return root;
}
//# of Nodes in tree
void size(Node *root)
{
//Check if end
if(root == NULL) return;
//Not end
else
{
bstSize = bstSize + 1;
size(root->left); //Visit left subtree
size(root->right); // Visit right subtree
}
}
void height(Node *root, int temp)
{
//Check if end
if(root == NULL)
{
if(temp > bstHeight)
{
bstHeight = temp;
}
return;
}
//Not end
else
{
temp = temp + 1;
height(root->left, temp); //Visit left subtree
height(root->right, temp); // Visit right subtree
}
}
//Function to visit nodes in Inorder
void show()
{
if(root == NULL) return;
show(root->left); //Visit left subtree
printf("%d ",root->data); //Print data
show(root->right); // Visit right subtree
}
void check(Node *root)
{
//End of a 'branch'
if(root == NULL) return;
int value = 0;
value = root->data;
//Checking left subtree
if(value < root->left->data)
{
//Tree is NOT valid
valid = 0;
}
//Checking right subtree
if(value > root->right->data)
{
//Tree is NOT valid
valid = 0;
}
check(root->left); //Visit left subtree
printf("%d ",root->data); //Print data
//check(root->right); // Visit right subtree
}
};
Node* root = NULL;
};
Specifically, in the show function. It's not as simple as putting it into Node with the rest of the functions, as root needs to be unique, and new Node is called at least once. Show will not compile in the current state, and I'm not sure where to proceed from here.
Though the comment says everything, let me give an additional hint:
When you want to keep your code as similar as possible to what you have now, try to add a constructor to the Node class that expects a pointer or reference (preferable) to the root and check, that each time you create a Node, you give the root to the constructor.
By the way, it might even be a better approach to look at some simple Node-based data structure implementations in C++, for example in the thread
Simple linked list in C++
I have checked other similar topics, but none seemed to help me.
I am trying to write a destructor for this specific BST implementation. Every node contains a pointer to the parent, a pointer to the left node, a pointer to the right node and a pointer to the value it contains.
This is how the beginning of the class looks:
#ifndef BST_H
#define BST_H
#include <iostream>
template <typename T>
class BST{
private:
BST<T> *left;
BST<T> *right;
BST<T> *parent;
T *value;
public:
BST() {
this->parent = NULL;
this->left = NULL;
this->right = NULL;
this->value = NULL;
}
~BST() {
removeRecursively(this);
}
void removeRecursively(BST<T>* node) {
if (node->left != NULL)
removeRecursively(node->left);
if (node->right != NULL)
removeRecursively(node->right);
if (node->left == NULL && node->right == NULL) {
if (node->parent->left == node)
node->parent->left = NULL;
if (node->parent->right == node)
node->parent->right = NULL;
node->parent = NULL;
node->value = NULL;
delete node->value;
delete node;
}
}
void add(T value) {
if (this->value == NULL) { // root-only case
this->value = new T;
*(this->value) = value;
}
else {
if (value < *(this->value)) {
if (this->left != NULL) // has left child
this->left->add(value);
else { // has no left child
this->left = new BST<T>;
this->left->value = new T;
this->left->parent = this;
*(this->left->value) = value;
}
}
else {
if (this->right != NULL) // has right child
this->right->add(value);
else { // has no right child
this->right = new BST<T>;
this->right->value = new T;
this->right->parent = this;
*(this->right->value) = value;
}
}
}
}
void inOrderDisplay() {
if (this->left != NULL)
this->left->inOrderDisplay();
std::cout << *(this->value) << " ";
if (this->right != NULL)
this->right->inOrderDisplay();
}
BST<T>* search(T value) {
if (*(this->value) == value)
return this;
else if (this->left != NULL && value < *(this->value))
return this->left->search(value);
else if (this->right != NULL && value > *(this->value))
return this->right->search(value);
else
return NULL;
}
BST<T>* remove(T value) {
BST<T>* node = search(value);
if (node != NULL) {
if (node->left == NULL && node->right == NULL) { // leaf node
delete node->value;
if (node->parent->left == node) // is left child
node->parent->left = NULL;
else // is right child
node->parent->right = NULL;
delete node;
}
// 1 child nodes
if (node->left != NULL && node->right == NULL) { // has left child
if (node->parent->left == node) // is left child
node->parent->left = node->left;
else // is right child
node->parent->right = node->left;
delete node->value;
node->parent = NULL;
delete node;
}
if (node->left == NULL && node->right != NULL) { // has right child
if (node->parent->left == node) // is left child
node->parent->left = node->right;
else // is right child
node->parent->right = node->right;
delete node->value;
node->parent = NULL;
delete node;
}
// 2 children nodes
if (node->left != NULL && node->right != NULL) {
T aux;
BST<T>* auxNode = node->right;
while (auxNode->left != NULL)
auxNode = auxNode->left;
aux = *(auxNode->value);
if (auxNode->right != NULL) {
*(auxNode->value) = *(auxNode->right->value);
auxNode->right->parent = NULL;
auxNode->right->value = NULL;
auxNode->right = NULL;
delete auxNode->right;
}
else {
if (auxNode->parent->left == auxNode) // is left child
auxNode->parent->left = NULL;
else // is right child
auxNode->parent->right = NULL;
auxNode->value = NULL;
delete auxNode;
}
*(node->value) = aux;
}
}
return this;
}
};
#endif // BST_H
The BST class is used as below:
BST<int>* root = new BST<int>();
root->add(5);
root->add(2);
root->add(-17);
root->inOrderDisplay();
root->remove(5);
I mention that all the methods work properly (I decided not to post them, since they are not the subject of this question). The problem is that when I run my test file with Valgrind, it detects some memory leaks and I am sure that they occur because of the lack of a proper destructor (the above one produces a segmentation fault).
EDIT: I added the code for the other methods
Thank you!
Your basic design is kind of broken, at least IMO. That is, if you're willing to jump through enough hoops, you can probably make it work, but even at best it'll probably always be at least a little clumsy to work with.
I'd start by defining a separate class for the nodes in the tree. Then the tree itself will hold a pointer to the root of the tree and define most of the interface to the tree.
template <class T>
class Tree {
struct node {
node *parent;
node *left;
node *right;
T *value;
node(T *value)
: parent(nullptr), left(nullptr), right(nullptr), value(new T(value))
{
}
~node() {
delete(left);
delete(right);
delete(value);
}
} *root;
Tree() : root(nullptr) {}
~Tree() {
delete(root);
}
};
Destruction doesn't have to be explicitly recursive. The delete(left) (for example) will invoke the dtor for the left child node (if there is one) and that'll invoke the dtor for its child nodes, and so on. When we reach a leaf node, we'll end up with (the equivalent of) delete nullptr;, which is defined as doing nothing, stopping the recursion.
You should swap the lines:
node->value = NULL;
delete node->value;
Like this:
delete node->value;
node->value = NULL;
if you first assign NULL you delete nothing.
The hardest bugs to find are the ones in the code you've decided not to look at because you've convinced yourself they're not relevant.
Anyways, there is one evident problem with your implementation: after removing a bunch of other stuff, you are basically doing
class foo
{
~foo() { delete this; }
};
Use RAII with unique_ptr to avoid those issues:
template <typename T>
class BST{
public:
BST() = default;
~BST() = default;
BST(const BST&) = delete;
BST& operator =(const BST&) = delete;
BST(BST&&) = delete;
BST& operator =(BST&&) = delete;
private:
std::unique_ptr<BST<T>> left;
std::unique_ptr<BST<T>> right;
BST<T>* parent = nullptr;
std::unique_ptr<T> value;
};
I am trying to understand BSTs and how to insert elements into it iteratively. My node structure implementation looks like so:
struct Node{
Node *left;
Node *right;
T data; //template class
};
And my insertion implementation looks like so:
template<typename T>
bool BST<T>::Insert(const T value)
{
Node *newNode = new Node;
newNode -> data = value;
newNode -> left = NULL;
newNode -> right = NULL;
if(root == NULL) {root = newNode;} //If the BST is empty
else
{//The BST is not empty
Node *ptr = root; //points to the current Node
Node *ptr_parent; //points to the parent Node
while(ptr != NULL)
{
if((ptr -> data) > value)
{
ptr_parent = ptr;
ptr = ptr -> left;
}
if((ptr -> data) < value)
{
ptr_parent = ptr;
ptr = ptr -> right;
}
}
}
ptr = newNode; //insert the newNode at the spot
if((ptr_parent -> data) < value)
ptr_parent -> right = newNode;
else
ptr_parent -> left = newNode;
return true;
}
The insertion works when adding the first Node into an empty tree but I get a segmentation fault whenever i try to add more Nodes. I understand that there are posts that show how to implement insertions into BSTs but most of them show the recursive method, and those with iterative examples are incomplete or too specific. Thank you.
I think I'd do things a little differently. First, I'd simplify the other code a little by adding a ctor to the Node class:
struct Node{
Node *left;
Node *right;
T data;
Node(T const &data) : left(nullptr), right(nullptr), data(data) {}
};
Then you can use a pointer to a pointer to traverse the tree and insert the item:
bool insert(const T value) {
Node **pos;
for (pos = &root; *pos != nullptr;) {
if (value < (*pos)->value)
pos = &(*pos)->left;
else if ((*pos)->value < value )
pos = &(*pos)->right;
else
return false;
}
*pos = new Node(value);
return true;
}
Note that I've delayed creating the new node until after we've dropped out of the loop. This way, if we have a duplicate element, we can just return (without leaking a node, since we haven't allocated a new node yet).
For what it's worth, if you were going to do this recursively, it would probably be easier to use a reference to a pointer instead of a pointer to a pointer.
I was able to make my original code work last night, I'm sharing the answer here:
template<typename T>
bool BST<T>::Insert(const T value)
{
Node *ptr;
Node *ptr_parent;
if(root == NULL)
{//The BST is Empty...
Node *newNode = new Node;
newNode -> data = value;
newNode -> left = NULL;
newNode -> right = NULL;
root = newNode;
ptr = root;
} else { //traversing the tree to find the insertion point
ptr = root;
while(ptr != NULL)
{
if((ptr -> data) == value) {return false;} //to check for duplicates
if(value < (ptr -> data))
{
ptr_parent = ptr;
ptr = ptr -> left;
} else {
ptr_parent = ptr;
ptr = ptr -> right;
}
}
Node *newNode = new Node;
newNode -> data = value;
newNode -> left = NULL;
newNode -> right = NULL;
//checking for parent value to determine if
//the Node is a left or right child
if(value < (ptr_parent -> data))
ptr_parent -> left = newNode;
else
ptr_parent -> right = newNode;
}
++count;//to keep track of the Node count
return true;
}
For my own sake I wanted to solve this without using double pointers.
You didn't handle the case when ptr->data == value so the loop will be infinite whenever a duplicate is found, and ptr = newNode doesn't do anything, it just makes ptr point to newNode. Try this
//ptr holds the address of pointers to nodes.
Node **ptr = &root;
while(*ptr != NULL){
if((*ptr)->data > T)
ptr = &(*ptr)->right;
else
ptr = &(*ptr)->left;
//Not handling duplicates
}
//Change the value of the pointer to newNode
*ptr = newNode;
Use hard pointers
Node **ptr = &root; //points to the current Node
Node **ptr_parent; //points to the parent Node
When you are trying to do this
ptr = newNode; //insert the newNode at the spot
it doesn't do anyithing because you need to modify the pointer which points to the left or the right subnode
something like this:
template<typename T>
bool BST<T>::Insert(const T value)
{
Node *newNode = new Node;
newNode -> data = value;
newNode -> left = NULL;
newNode -> right = NULL;
if(root == NULL) {root = newNode;} //If the BST is empty
else
{//The BST is not empty
Node **ptr = &root; //points to the current Node
Node **ptr_parent; //points to the parent Node
while((*ptr) != NULL)
{
if(((*ptr) -> data) > value)
{
ptr_parent = ptr;
ptr = &ptr -> left;
}
if(((*ptr) -> data) < value)
{
ptr_parent = ptr;
ptr = &ptr -> right;
}
}
}
(*ptr) = newNode; //insert the newNode at the spot
if(((*ptr_parent) -> data) < value)
(*ptr_parent) -> right = newNode;
else
(*ptr_parent) -> left = newNode;
return true;
}
As I understand, it is failing because of following line:
ptr = newNode; //insert the newNode at the spot
after the while loop your ptr is NULL otherwise you can not exit from the while loop. You are assigning a struct to NULL, which is not right.
Hopefully this helps. Everything else looks normal.
void insert(node* root, int value)
{
if (root == NULL)
{
root = new node;
root->data = value;
return;
}
while(!((root->data < value && root->right == NULL) || (root->data >= value && root->left == NULL)))
{
if (root->data < value)
root = root->right;
else
root = root->left;
}
if (root->data < value)
{
root->right = new node;
root->right->data = value;
} else
{
root->left = new node;
root->left->data = value;
}
}
template <class T>
class TreeNode{
private:
T data;
TreeNode<T>* right,*left;
public:
void setData(T d){
this->data =d;
}
T getData(){
return this->data;
}
void setRight(TreeNode<T>* r){
this->right =r;
}
TreeNode<T>* getRight(){
return this->right;
}
void setLeft(TreeNode<T>* r){
this->left =r;
}
TreeNode<T>* getLeft(){
return this->left;
}
static TreeNode<T>* newNode(T data){
TreeNode<T>* n = new TreeNode<T>();
n->setData(data);
n->setRight(NULL);
n->setLeft(NULL);
return n;
}
};
template <class T>
class BinaryTree{
private:
TreeNode<T>* root;
public:
void insert(T data){
TreeNode<T>* n = TreeNode<T>::newNode(data);
if(root==NULL)
root = n;
else{
TreeNode<T>* t = root;
while(t!=NULL){
if(n->getData() >= t->getData()){
if(t->getRight()==NULL){
t->setRight(n); //newnode attached as right child in tree
t = NULL;
}
else
t = t->getRight();
}
else{
if(t->getLeft()==NULL){
t->setLeft(n); //newnode attached as left child in tree
t=NULL;
}
else
t = t->getLeft();
}
}
}
}
void preorder(){
TreeNode<T>* t = root;
preorderUtil(t);
}
void preorderUtil(TreeNode<T>* node){
if(node==NULL)
return;
preorderUtil(node->getLeft());
cout<<node->getData()<<" ";
preorderUtil(node->getRight());
}
};
I answered a case here Binary Search Tree insertion doesn't work see if it helps
void insert(int val)
{
Node *newNode;
newNode=new Node;
newNode->data=val;
Node *currentNode=root;
Node *parentNode;
if(root==NULL)
{
newNode->left=NULL;
newNode->right=NULL;
}
else
{
while(currentNode!=NULL)
{
if((currentNode->data)>val)
{
parentNode=currentNode;
currentNode=currentNode->left;
}
if((currentNode->data)<val)
{
parentNode=currentNode;
currentNode=currentNode->right;
}
}
}
currentNode=newNode;
if((parentNode->data)<val)
{
parentNode->right=newNode;
}
else
{
parentNode->right=newNode;
}
}
I have written an implementation of BST-Tree but the key can be only string type. I would like to use that tree with other types of keys. I know that I would have to define a template, but do not know how to do it so the key will have T type. The examples show all but not important stuff.
using namespace std;
int ASCENDING = 0, DESCENDING = 1;
class Node {
public:
string key; //I would like to change type to T
Node* left;
Node* right;
Node(string key) {
this->key = key;
left = NULL;
right = NULL;
}
};
class BST {
public:
Node* root;
BST(string key) {
root = new Node(key);
}
void insert(string value){
if(root == NULL)
root = new Node(value);
else
insertHelper(root, value);
}
void insertHelper(Node* node, string value){
if(value < node->key){
if(node->left == NULL)
node->left = new Node(value);
else
insertHelper(node->left, value);
}
else{
if(node->right == NULL)
node->right = new Node(value);
else
insertHelper(node->right, value);
}
}
void print(int order){
show(order, root);
}
~BST(){
//delete all nodes
}
private:
void show(int order, Node* n){
Node* pom = n;
if(order == ASCENDING){
if(pom != NULL){
show(order, n->left);
cout<<n->key<<endl;
show(order, n->right);
}
}else{
if(pom != NULL){
show(order, n->right);
cout<<n->key<<endl;
show(order, n->left);
}
}
}
};
This should cover the basic setup and the rest of the changes should be similar:
template <typename T>
class Node {
public:
T key; //I would like to change type to T
^^^^^ Type now T
Node<T>* left;
Node<T>* right;
Node(T key) {
this->key = key;
left = NULL;
right = NULL;
}
};
template <typename T>
class BST {
public:
Node<T>* root;
^^^^^^^ Node now will become Node<T> in the rest of the code as well
BST(T key) {
root = new Node<T>(key);
}
// rest of code
};
I'm trying to make a BST and need to print it inorder, postorder, and preorder.
The thing am not sure about is how to create this tree in my main() function.
struct Tree_Node
{
Tree_Node *right;
Tree_Node *left;
int info;
};
class bTree
{
private:
Tree_Node *root;
public:
bTree();
void bTree::Insert(Tree_Node*& tree, int item);
void bTree::preorderPrint(Tree_Node *root);
};
bTree::bTree()
{
root = NULL;
}
void bTree::Insert(Tree_Node*& tree, int item)
{
if (tree == NULL)
{
tree = new Tree_Node;
tree->right = NULL;
tree->left = NULL;
tree->info = item;
}
else if (item < tree->info)
Insert(tree->left, item);
else
Insert(tree->right, item);
}
void bTree::preorderPrint(Tree_Node *root)
{
if ( root != NULL )
{
cout << root->info << " ";
preorderPrint( root->left );
preorderPrint( root->right );
}
}
void main()
{
// This is where I need help at
// I'm not sure how to insert a new node
bTree Test;
Test.Insert(
}
By the looks of things, you can just write
Test.Insert(Test.root, 3); // Insert 3
Test.Insert(Test.root, 4); // Insert 4
and that should work. Of course, you'll have to make root public.
However, this is a bit awkward, since the first parameter will always be bTree.root - and you don't need to make that public. Remember that the user of your data type (you or anyone else) shouldn't have to care about internals such as nodes - they only care about their data. Instead, I'd recommend making a convenience Insert method which only needs to take an integer (not a tree node) - this is called Overloading.
void bTree::Insert(int item)
{
Insert(root, item);
}
// Keep the other insert method, but make it private.
Then you can just write:
Test.Insert(3);
Test.Insert(4);
void bTree::Insert(int item)
{
Tree_Node * node = new Tree_Node;
node->left = NULL;
node->right = NULL;
node->info = item;
if (root == NULL)
{
root = node;
return;
}
Tree_Node * t = root;
Tree_Node * p = root;
while(1)
{
if (item < t->info)
{
t = t->left;
if(t == NULL)
{
p->left = node;
return;
}
}
else if(item > t->info)
{
t = t->right;
if(t == NULL)
{
p->right = node;
return;
}
}
else //item already exists in the tree
return;
p = t;
}
}
//now you can insert nodes like
Test.Insert(5);
Test.Insert(6);