C++ - BST segmentation fault upon deletion of node with 2 children - c++

Segmentation faults when trying to delete a node with 2 children
So i've recently started studying algorithms and have been working a bit on binary search trees, basing my C++ code on the pseudo code taken from the book Introduction to Algorithms. I'm however having large issues with it's delete function for it's binary search tree. The code for the delete function is:
void bstDelete(BSTtree &bst, int key)
{
treeNode *z = findNode(bst, key);
if (z != nullptr)
{
treeNode *y = z;
treeNode *x;
if (z->left == bst.NIL)
{
x = z->right;
transplant(bst, z, z->right);
}
else if (z->right == bst.NIL)
{
x = z->left;
transplant(bst, z, z->left);
}
else
{
y = treeMin(z->right);
x = y->right;
if (y->parent == z)
{
x->parent = y;
}
else
{
transplant(bst, y, y->right);
y->right = z->right;
y->right->parent = y;
}
transplant(bst, z, y);
y->left = z->left;
y->left->parent = y;
}
}
}
Transplant function:
void transplant(BSTtree &bst, treeNode *u, treeNode *v)
{
if (u->parent == bst.NIL)
{
v->right = u->right;
v->left = u->left;
v->right->parent = v;
v->left->parent = v;
bst.root = v;
}
else if (u == u->parent->left)
{
u->parent->left = v;
}
else
{
u->parent->right = v;
}
v->parent = u->parent;
}
I'm not expecting someone to debug my code, I've just sat pretty much for multiple days trying to figure it out, looking at other people's versions of the delete function trying to understand why mine doesn't work. There's also the issue of why the book's own delete function doesn't do it's job, or if it's just me who's at fault. I would really appreciate if someone could take a look at this. I've been looking around quite a lot and still haven't found anyone having issues with this.
Edit
Added other parts related to the code
treeNode *findNode(RBtree bst, int key)
{
treeNode *z = nullptr;
treeNode *x = bst.root;
treeNode *y = bst.NIL;
while (x != nullptr && x != bst.NIL)
{
y = x;
if (key < x->value)
{
x = x->left;
}
else
{
x = x->right;
}
if (y->value == key)
{
break;
}
}
if (y->value == key)
{
z = y;
}
return z;
}
treeNode *treeMin(treeNode *root)
{
treeNode *treeNode = root;
while (treeNode->left != nullptr)
{
treeNode = treeNode->left;
}
return treeNode;
}
struct treeNode
{
treeNode *left;
treeNode *right;
treeNode *parent;
std::string color;
int value;
treeNode() : left(nullptr), right(nullptr), parent(nullptr) {}
treeNode(int paramValue) : left(nullptr), right(nullptr), parent(nullptr), value(paramValue) {}
treeNode(int paramValue, treeNode *parent) : value(paramValue), parent(parent) {}
};
struct BSTtree
{
treeNode *root;
treeNode *NIL;
BSTtree()
{
NIL = new treeNode();
root = nullptr;
}
};
Reason i have with NIL is so that i can easier make this into an RB tree later on. The smallest scale needed to cause a crash is a 3 node tree, where you have a root, and it has a right and left child. That way you push the delete function into case three, where it has to find a successor and transplant it. It's in this part of the delete-function which it crashes and gives me a segmentation-fault.
Edit 2
Code which causes a crash:
int main()
{
BSTtree bst;
bstInsert(bst, 5);
bstInsert(bst, 7);
bstInsert(bst, 2);
bstDelete(bst, 5);
}
Insert function
void bstInsert(BSTtree &bst, int key)
{
treeNode *z = new treeNode(key);
treeNode *y = bst.NIL;
treeNode *x = bst.root;
while (x != nullptr && x != bst.NIL)
{
y = x;
if (z->value < x->value)
{
x = x->left;
}
else
{
x = x->right;
}
}
z->parent = y;
if (y == bst.NIL)
{
bst.root = z;
z->parent = bst.NIL;
}
else if (z->value < y->value)
{
y->left = z;
}
else
{
y->right = z;
}
z->left = bst.NIL;
z->right = bst.NIL;
}
The nullptr is not a problem here as it's resolved in the insert function, as you can see if it's root, root is given bst.NIL as it's parent. I agree it's error prone to have this construction, it's only there to be able to be used for red and black trees which uses a specific NIL node instead of nullptr.

I've resolved the issues, firstly the treeMin() function is faulty. It should take in an additional parameter which is BSTtree bst and instead of while (treeNode->left != nullptr) it should be while (treeNode->left != bst.NIL), outside of this one of the constructors in treeNode is faulty, this one being treeNode(int paramValue, treeNode *parent) : value(paramValue), parent(parent) {}, it should instead be changed into:
treeNode(int paramValue, treeNode *paramParent) {
value = paramValue;
parent = paramParent;
}

Related

Red Black Tree implementation using CLRS method. Having trouble spotting my errors

I'm having trouble implementing the CLRS method for a Red Black Tree. I'm not able to successful insert and I don't know what I'm doing wrong. I struggle with pointers and it's a topic I'm trying to learn more about (I'm buying a book on Amazon this weekend to learn more). Please help me pin point errors. I'm not receiving error messages, but my code won't run past my RBTInsert function, so I know it's getting stuck there. I call RBT Insert in another function that's not shown, but I didn't show it because I'm convinced my errors are in my pointers and nodes.
enum Color {RED, BLACK};
template <typename T>
struct Node
{
T data;
bool color;
Node<T>* left = nullptr;
Node<T>* right = nullptr;
Node<T>* p = nullptr; //p is parent
}
template <typename T>
class RBT
{
private:
Node<T>* root;
void RotateLeft(Node<T>*, Node<T>*);
void RotateRight(Node<T>*, Node<T>*);
void RBTFixUp(Node<T>*, Node<T>*);
void MakeEmpty(Node<T>* root);
public:
RBT(): root(nullptr){}
~RBT();
void RBTInsert(Node<T>* &root, T data);
};
template <typename T>
void RBT<T>::MakeEmpty(Node<T>* root)
{
while (root != nullptr)
{
delete root;
MakeEmpty(root->left);
MakeEmpty(root->right);
}
}
template <typename T>
RBT<T>::~RBT()
{
MakeEmpty(root);
}
template <typename T>
void RBT<T>::RotateLeft(Node<T>* root, Node<T>* x)
{
Node<T>* y = x->right;
x->right = y->left;
if (y->left != nullptr)
y->left->p = x;
y->p = x->p;
if (x->p == nullptr)
root = y;
else if (x == x->p->left)
x->p->left = y;
else
x->p->right = y;
y->left = x;
x->p = y;
}
template <typename T>
void RBT<T>::RotateRight(Node<T>* root, Node<T>* x)
{
Node<T>* y = x->left;
x->left = y->right;
if (y->right != nullptr)
y->right->p = x;
y->p = x->p;
if (x->p == nullptr)
root = y;
else if (x == x->p->right)
x->p->right = y;
else
x->p->left = y;
y->right= x;
x->p = y;
}
template <typename T>
void RBT<T>::RBTFixUp(Node<T>* root, Node<T>* z)
{
while (z->p->color == RED)
{
if (z->p == z->p->p->left)
{
Node<T>* y = z->p->p->right;
if(y->color == RED)
{
z->p->color = BLACK;
y->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}else if (z == z->p->right)
{
z = z->p;
RotateLeft(root,z);
}
}else
{
Node<T>* y = z->p->p->left;
if(y->color == RED)
{
z->p->color = BLACK;
y->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}else if (z == z->p->left)
{
z = z->p;
RotateRight(root,z);
}
}
}
}
template <typename T>
void RBT<T>::RBTInsert(Node<T>* &root, T data)
{
Node<T>* z = nullptr;
z->data = data;
Node<T>* y = nullptr;
Node<T>* x = nullptr;
while (x != nullptr)
{
y = x;
if (z->data < x->data)
x = x->left;
else
x = x->right;
}
z->p = y;
if (y == nullptr)
root = z;
else if (z->data < y->data)
y->left = z;
else
y->right = z;
z->left = nullptr;
z->right = nullptr;
z->color = RED;
RBTFixUp(root,z);
}

C++ Binary Tree Traversal Inorder, Preorder and Postorder

I'm currently working on a C++ project and part of it is to traverse the binary tree using inorder, preorder, and postorder.
class TNode
{
public:
int val;
TNode() {}
TNode(int v) { val = v; }
TNode * left;
TNode * right;
TNode * parent;
};
class BTree
{
void print_pre_order(TNode *r);// print the node as you traverse according to the order.
void print_in_order();
void print_post_order();
}
BTree::BTree()
{
root = new TNode(1);
root->parent = 0;
root->left = new TNode(2);
root->right = new TNode(3);
root->left->left = new TNode(4);
root->left->right = new TNode (5);
root->right->left = new TNode(6);
}
void BTree::print_pre_order(TNode *r)
{
if (r == 0)
{
return;
}
cout << r->val;
print_pre_order(r->left);
print_pre_order(r->right);
}
int main()
{
BTree y;
y.print_pre_order(y.root);
return 0;
}
In my default constructor, I've initialized values for some nodes, but when I run the code, the output I'm getting is "124" and gets an error. I don't know where I did wrong, can someone help?
I see no signs that the program ever sets any any pointers to zero, so if (r == 0) is unlikely to ever trigger an exit.
Give this a try:
class TNode
{
public:
int val;
TNode(): val(0), left(nullptr), right(nullptr), parent(nullptr) {}
TNode(int v): val(v), left(nullptr), right(nullptr), parent(nullptr) {}
TNode * left;
TNode * right;
TNode * parent;
};
The : tells the compiler that a member initializer list is coming. After that the code initializes all of the pointer members to point at null.
Change the
if (r == 0)
to
if (r == nullptr)
to better convey intent and you should be good to go.

C++ Binary Search Tree Implementation

I am working on a project in C++ in which I have to create a binary search tree that inserts items from an array. I have to use the following insert algorithm:
tree-insert(T, z)
y = NIL
x = T.root
while x != NIL
y = x
if z.key < x.key
x = x.left
else x = x.right
z.p = y
if y == NIL
T.root = z
else if z.key < y.key
y.left = z
else y.right = z
Here is what I have so far:
#include <iostream>
using namespace std;
struct node
{
int key;
node* left;
node* right;
node* p;
node* root;
};
void insert(node*, node*);
void printinorder(node*);
int main()
{
node *root;
node* tree = new node;
node* z = new node;
int array [10] = {30, 10, 45, 38, 20, 50, 25, 33, 8, 12};
for (int i = 0; i < 10; i++)
{
z->key = array[i];
insert(tree, z);
}
printinorder(tree);
return 0;
}
void insert(node *T, node *z)
{
node *y = nullptr;
node* x = new node;
x = T->root;
while (x != NULL)
{
y = x;
if (z->key < x->key)
x = x->left;
else
x = x->right;
}
z->p = y;
if (y == NULL)
T->root = z;
else if (z->key < y->key)
y->left = z;
else
y->right = z;
}
void printinorder(node *x)
{
if (x != NULL)
{
printinorder(x->left);
cout << x->key << endl;
printinorder(x->right);
}
}
This code compiles however when I run it, it seg faults. I believe the problem has something to do with the nodes I am creating or my function calls.
Thanks for your help.
Besides the issues noted in the comments, the biggest bug in this code is a lack of a constructor that initializes all pointers in a new node to NULL.
As such, every node you create will have its pointers containing random garbage. You code initializes some of them, but most are not. Trying to use uninitialized pointers will result in an immediate crash.
You need to fix all the problems that have been noted in the comments, and have a proper constructor for your node class.

Why does printing a pointer address trigger a breakpoint?

I am trying to implement a binary tree for learning purposes. When I first got the error I thought maybe I was deleting a node twice. Then I realised that even the print statement is triggering a breakpoint. There is no deletion anywhere else in the entire program so the problem has to be here.
here is BinaryTree.cpp
#include "BinaryTree.h"
#include<iostream>
BinaryTree::BinaryTree(void):root(nullptr){}
BinaryTree::~BinaryTree(void){removeWithChildren(root);}
void BinaryTree::insert(Node *n){
cout<<"\nInserting: "<<(void*)n;
Node *y = nullptr;
Node *x = root;
while(x != nullptr){
y = x;
if(n->key < x->key)
x = x->left;
else
x = x->right;
}
n->parent = y;
if(y == nullptr)
root = n;
else if (n->key < y->key)
y->left = n;
else
y->right = n;
}
void BinaryTree::removeWithChildren(Node *n){
//forgetChild(n);
if(n->left)
removeWithChildren(n->left);
if(n->right)
removeWithChildren(n->right);
cout<<"\nDeleting: "<<(void*)n;
delete n;
}
void BinaryTree::remove(Node *n){
if(n->left == nullptr) {
transplant(n,n->right);
} else if(n->right == nullptr) {
transplant(n,n->left);
} else {
Node *y = minimum(n->right);
if(y->parent != n){
transplant(y,y->right);
y->right = n->right;
y->left = n->left;
}
transplant(n,y);
y->left = n->left;
y->left->parent = y;
}
cout<<"\nDeleting: "<<(void*)n;
delete n;
}
void BinaryTree::transplant(Node *u,Node *v){
if(u->parent == nullptr) root = v;
else if (u == u->parent->left) u->parent->left = v;
else u->parent->right = v;
if(v) v->parent == u->parent;
}
string BinaryTree::prewalk(Node *n){
string output = "";
if(n!=nullptr){
output += prewalk(n->left);
output += prewalk(n->right);
output += to_string(n->key);
}
return output;
}
string BinaryTree::inwalk(Node *n){
string output = "";
if(n!=nullptr){
output += inwalk(n->left);
output += to_string(n->key);
output += inwalk(n->right);
}
return output;
}
Node* BinaryTree::search(Node *sub_tree,int key){
if(sub_tree == nullptr) return nullptr;
if(sub_tree->key == key) return sub_tree;
if(sub_tree->key < key) return search(sub_tree->right,key);
else return search(sub_tree->left,key);
}
Node* BinaryTree::getSuccessor(Node *n){
if(n->right)
return minimum(n->right);
Node *y = n->parent;
while(y){
if(n != y->right) break;
n = y;
y = y -> parent;
}
return y;
}
Node* BinaryTree::minimum(Node *sub_tree){
while(sub_tree->left)
sub_tree = sub_tree ->left;
return sub_tree;
}
Node* BinaryTree::maximum(Node *sub_tree){
while(sub_tree->right)
sub_tree = sub_tree ->right;
return sub_tree;
}
void BinaryTree::forgetChild(Node *n){
if(n->parent){
if(n == n->parent->left) n->parent->left = nullptr;
else n->parent->right = nullptr;
}
}
Here is main.cpp
#include"BinaryTree.h"
#include<iostream>
#include<random>
using namespace std;
int main(){
{
BinaryTree bt;
bt.insert(new Node(5));
bt.insert(new Node(1));
bt.insert(new Node(3));
bt.insert(new Node(4));
bt.insert(new Node(9));
//cout<<bt.inwalk(bt.getRoot())<<endl;
bt.remove(bt.search(bt.getRoot(),3));
//cout<<bt.inwalk(bt.getRoot())<<endl;
}
char x;cin>>x;
return 0;
}
Here is BinaryTree.h
#pragma once
#include<string>
using namespace std;
struct Node{
Node *left,*right,*parent;
int key;
Node():left(nullptr),right(nullptr),parent(nullptr),key(0) {}
Node(int x):left(nullptr),right(nullptr),parent(nullptr),key(x) {}
};
class BinaryTree
{
private:
Node *root;
public:
BinaryTree(void);
~BinaryTree(void);
Node* getRoot() { return root; }
void insert(Node *n);
void removeWithChildren(Node *n);
void remove(Node *n);
string prewalk(Node *n);
string inwalk(Node *n);
Node* search(Node *sub_tree,int key);
Node* minimum(Node *sub_tree);
Node* maximum(Node *sub_tree);
Node* getSuccessor(Node *n);
void forgetChild(Node *n);
void transplant(Node* u,Node*v);
};
The destructor calls the removeWithChildren(Node *n) function and the argument being the root of the tree.
I am calling the remove(Node *n) once. When I do not call it, there is no error. I stepped through and inspected the code, the removeWithChildren function is not trying to delete the node which was deleted by the remove function. Still there is an error.
EDIT: I am on Microsoft Visual Studio 2012 Express edition.
I don't know what kind of breakpoint.
EDIT2: Commenting out forgetChild in removeWithChildren fixes the error for some reason.
You did not post the relevant part of your code, but what you posted leads to the guess that you provided neither a valid copy constructor, nor any prevention of use of the default copy constructor. Then you made the mistake of passing an object by value (when you should have passed by reference) thus invoking the default copy constructor and the destructor and corrupting memory.
When working with classes for which copy construction is difficult and probably unnecessary, make sure the default copy constructor is not reachable.

What wrong with my Red Black Tree destructor?

I'm building a Red-Black Tree, but may be there are some problems with my class RBTree's destructor. I add 10^7 value to the tree, and then call the destructor, but the memory seem to be not freed up. (I look at the System Monitor and my program still use 200MB).
Could you tell me what is wrong with my destructor. This is my source code.
Sorry for my poor English.
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
enum Color {RED, BLACK};
template<class Data> class RBNode;
template<class Data> class RBTree;
template<class Data> class RBNode {
Color color; RBNode *p, *left, *right;
public:
Data v;
RBNode(Color color, RBNode *p, RBNode *left, RBNode *right, Data v):
color(color), p(p), left(left), right(right), v(v) {}
RBNode() {}
friend class RBTree<Data>;
};
template<class Data> class RBTree {
typedef RBNode<Data> Node;
typedef Node * PNode;
PNode root, nil;
void LeftRotate(PNode x) {
PNode y = x->right; x->right = y->left;
if(y->left != nil) y->left->p = x;
y->p = x->p;
if(x->p == nil) root = y;
else if(x == x->p->left) x->p->left = y;
else x->p->right = y;
y->left = x; x->p = y;
}
void RightRotate(PNode y) {
PNode x = y->left; y->left = x->right;
if(x->right != nil) x->right->p = y;
x->p = y->p;
if(y->p == nil) root = x;
else if(y == y->p->left) y->p->left = x;
else y->p->right = x;
x->right = y; y->p = x;
}
void insertFixUp(PNode z) {
while(z->p->color == RED) {
if(z->p == z->p->p->left) {
PNode y = z->p->p->right;
if(y->color == RED) z->p->color = y->color = BLACK, z->p->p->color = RED, z = z->p->p;
else {
if(z == z->p->right) LeftRotate(z = z->p);
z->p->color = BLACK; z->p->p->color = RED; RightRotate(z->p->p);
}
} else {
PNode y = z->p->p->left;
if(y->color == RED) z->p->color = y->color = BLACK, z->p->p->color = RED, z = z->p->p;
else {
if(z == z->p->left) RightRotate(z = z->p);
z->p->color = BLACK; z->p->p->color = RED; LeftRotate(z->p->p);
}
}
}
root->color = BLACK;
}
public:
RBTree() {
nil = new Node;
nil->color = BLACK;
nil->p = nil->left = nil->right = nil;
nil->v = Data();
root = nil;
}
~RBTree() {
delete root;
delete nil;
}
void insert(Data v) {
PNode y = nil, x = root;
while(x != nil) {
y = x;
x = v < x->v ? x->left : x->right;
}
PNode z = new Node; *z = Node(RED, y, nil, nil, v);
if(y == nil) root = z;
else if(v < y->v) y->left = z;
else y->right = z;
insertFixUp(z);
}
};
int main() {
RBTree<int> tree;
for(int i = 0; i < 10000000; ++i) tree.insert(i);
tree.~RBTree();
getchar();
return 0;
}
You need to add a destructor to your RBNode, which deletes its children:
template<class Data> class RBNode {
...
~RBNode() {
delete left;
delete right;
}
...
};
As is, you will delete the root node when the tree is deleted, but the root node itself doesn't free its resources. Because of this, you lose all references to the child nodes of root, and all their child nodes, etc. Because you no longer have a reference to these nodes, you can't delete them, you have a memory leak.
The destructor ensures that when we're about to lose our references to a node's children, these children get freed (and their children and so on).
First, what's wrong with it is that you did not use a smart pointer. Secondly, you did not use a smart pointer in your Node classes, so when the root is deleted, none of the other objects are deleted.
Your tree nodes don't appear to recursively delete their children. You need a destructor in the node and then everything will cascade when the root gets destroyed.
Your destructor only frees up two elements: root and nil. To free up the rest of the tree, you should somehow propagate freeing up the elements down the tree, like:
~RBNode() {
if (left != nil ) delete left;
if (right != nil) delete right;
}
(this is just the idea, of course this code won't literally work because you don't see nil in the destructor).
I found my destructor, but i had some more attributes, like size and the parent pointer, but i think it will help
~RBTree() {
RBNode *p(root);
while(size!=0) {
if(p==root && size==1) { delete root; size--;}
else if(p->right!=0) p=p->right;
else if(p->left!=0) p=p->left;
else {
RBNode *c(p);
p=p->parent;
if(p->left==c) {
delete c;
p->left=0;
}
else {
delete c;
p->right=0;
}
size--;
}
}
}