C++ Segmentation fault -- Self-balancing Tree insertion - c++

I'm trying to solve a self-balancing tree problem on Hackerrank (https://www.hackerrank.com/challenges/self-balancing-tree/problem) and I keep getting a Segmentation fault in the last 3 test cases. I saw that this same problem had been posted before and tried to apply the same approach (check for nullptr) to my case, but no success so far. The following code is written in C++ and I would appreciate a lot if you guys could help me out. Thanks!
/* Node is defined as :
typedef struct node
{
int val;
struct node* left;
struct node* right;
int ht;
} node; */
node * newNode(int val)
{
node * newNode = new node;
newNode->val = val;
newNode->left = nullptr;
newNode->right = nullptr;
newNode->ht = 0;
return newNode;
}
int getHeight(node* root)
{
if(root == nullptr) {
return -1;
} else {
return root->ht;
}
}
node* rightRotate(node* root)
{
node* temp = root->left;
root->left = temp->right;
temp->right = root;
root->ht = 1 + max(getHeight(root->left), getHeight(root->right));
temp->ht = 1 + max(getHeight(temp->left), getHeight(temp->right));
return temp;
}
node* leftRotate(node* root)
{
node* temp = root->right;
root->right = temp->left;
temp->left = root;
root->ht = 1 + max(getHeight(root->left), getHeight(root->right));
temp->ht = 1 + max(getHeight(temp->left), getHeight(temp->right));
return temp;
}
node * insert(node * root,int val)
{
if(root == nullptr) {
root = newNode(val);
return root;
}
if(val > root->val) {
root->right = insert(root->right, val);
}
else if(val < root->val) {
root->left = insert(root->left, val);
}
else{ return 0; }
root->ht = 1 + max(getHeight(root->left),getHeight(root->right));
int balance = getHeight(root->left) - getHeight(root->right);
if(root->left != nullptr && balance > 1) {//Left subtree disbalanced
if(val < root->left->val) {
//Left-Left case: perform a right rotation on the disb. node
return rightRotate(root);
}
else {
//Left-Right case: perfom a left rotation on the disb. node left subtree
//and a right rotation on the disb. node
root->left = leftRotate(root->left);
return rightRotate(root);
}
}
if(root->right != nullptr && balance < -1) {//Right subtree disbalanced
if(val > root->right->val) {
//Right-Right case: perform a left rotation on the disb. node
return leftRotate(root);
}
else {
//Right-Left case: perfom a right rotation on the disb. node right subtree
//and a left rotation on the disb. node
root->right = rightRotate(root->left);
return leftRotate(root);
}
}
return root;
}
Edit:
For debugging purposes I've used an online gdb and added to the code above the following traversal method and main function:
void inOrder(node* root) {
if(root == NULL) {
return;
} else {
inOrder(root->left);
cout << root->val << " ";
inOrder(root->right);
}
}
int main()
{
node* root=NULL;
root=insert(root,2);
root=insert(root,4);
root=insert(root,3);
inOrder(root);
return 0;
}
After trying to insert the values 2, 4 and 3, in this order, we would have a disbalanced tree since the right subtree would have a height of 1 while the left subtree would have a height of -1 (leaf node is nullptr) and the balance factor would be less than -1. Further analysis shows that we have a RIGHT-LEFT case since the node causing the disbalance is the left child of the right child of the disbalanced node (root 2). We would then have to perform a right rotation on the disbalanced node right child followed by a left rotation on the disbalanced node itself, and the tree should end up looking like the following:
3
/ \
2 4

Thanks to everyone who tried helping me out on this one, it turns out there is no limit to how dumb I can be. I believe I've figured out what I had done wrong.
The problem in this question lies on the section that checks if the right subtree is disbalanced and, if so, performs the necessary rotations. On the code piece below, it should be
root->right = rightRotate(root->right);
instead of
root->right = rightRotate(root->left);

Related

counting the number of vertices in a subtree

I wrote an AVL tree, I'm sure that it works correctly, but my vertex counting does not work for the subtree. Help find a mistake.
I am sure that the error is in this part of the delete function, if this is not enough, I will write its full part.
If I’m fundamentally wrong, then tell me how to implement the algorithm for finding the number of vertices in a subtree for an AVL tree
class Node
{
public:
int key;
Node *left;
Node *right;
int height;
int kol; // number of vertices in the subtree
};
Node* newNode(int key){
Node* node = new Node();
node->key = key;
node->left = nullptr;
node->right = nullptr;
node->height = 1;
node->kol = 1;
return node;
}
Node* minValueNode(Node* node){
Node* current = node;
while (current->left != nullptr)
current = current->left;
return current;
}
Node* deleteNode(Node* root, int key)
{
if (root == NULL)
return root;
if ( key < root->key ){
root->left = deleteNode(root->left, key);
root->kol--;
}
else if( key > root->key ){
root->right = deleteNode(root->right, key);
root->kol--;
}
else
{
if( (root->left == NULL) ||
(root->right == NULL) )
{
Node *temp = root->left ?
root->left :
root->right;
if (temp == NULL)
{
temp = root;
root = NULL;
}
else
{
int t = root->kol;
*root = *temp;
root->kol = t - 1;
}
free(temp);
}
else
{
Node* temp = minValueNode(root->right);
root->key = temp->key;
//root->kol = temp->kol;
root->right = deleteNode(root->right,
temp->key);
}
}
if (root == NULL)
return root;
return root;
}

How to combine findMin() and delete() to remove smallest node in a BST?

I have a recRemove function that recursively removes the given node. I also have a findMin function that finds the smallest node in the BST. I'm having trouble merging the two so that I can remove the smallest(or largest) node. This is what I tried doing but it just returned garbage: Full code: https://pastebin.com/HCVsUZ4S
//remove min node in BST
node * extractMin()
{
return recRemove(root, findMin(root));
}
//delete node from tree
node * recRemove(node * root, double data)
{
//3 cases: no children, one child, 2 children
if (root == NULL)
{
return NULL;
}
else if (data < root->data)
{
root->left = recRemove(root->left, data);
}
else if(data > root->data)
{
root->right = recRemove(root->right, data);
}
else
{
if (root->right == NULL && root->left == NULL) //no children
{
delete root;
root = NULL;
return root;
}
else if(root->left == NULL) //only right child
{
temp = root;
root = root->right;
delete temp;
return root;
}
else if(root->right == NULL) //only left child
{
temp = root;
root = root->left;
delete temp;
return root;
}
else //2 children
{
temp->data = findMin(root->right);
root->data = temp->data;
root->right = recRemove(root->right, temp->data);
}
}
return root;
}
//find min node in BST
double findMin(node * p)
{
if(p == NULL)
{
return -1;
}
else
{
//in a balanced BST the minimum node is the leftmost node so,
//we traverse the left subtree until we get to the leftmost node and return and remove it.
temp = p;
while(temp->left != NULL)
{
temp = temp->left;
}
return temp->data;
}
}
sorry , can't write comments yet (will delete this later)
Where is temp defined? If it is a global variable than this is probably the issue...
Edit:
Have now seen the pasebin.....
temp is a member variable. Change it to a local variable.
Make sure to delete it before leaving the function. (best use std::unique_ptr<>)

How do I access a pointer from within a nested class?

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++

AVL Tree Traversal from outside Tree class

I am having some trouble with a Tree comparison program I am writing in C++. I am trying to traverse a tree to compare elements in another tree from a comparator class, and I am getting an error that says that I cannot access root in the AVL tree class. The error I am getting is:'class avlTree' has no member named 'root.' Below is my code for the method in question, and after that is the AVL Tree class. I am beginning to wonder if I should pass in the second tree to be compared in the method call to a method within the AVL Tree class, and just traverse the tree, and call to the second tree from within the Tree class. I am very much a beginner at C++, so I apologize in advance for any confusion and/or poor style.
Method
void findCommon(){
if(tree.root == NULL){
return;
}
findCommon(tree.root->left);
if (tree2.find(tree.root) == true){
cout<<tree.root->data<<" ";
}
findCommon(tree.root->right);
}
AVL Tree Class
#include<iostream>
#include<cstdio>
#include<sstream>
#include<algorithm>
#include<string>
#define pow2(n) (1 << (n))
using namespace std;
/*
* Node Declaration
*/
struct avl_node
{
string data;
struct avl_node *left;
struct avl_node *right;
}*root;
/*
* Class Declaration
*/
class avlTree
{
public:
avlTree()
{
root = NULL;
}
/*
* Height of AVL Tree
*/
int height(avl_node *temp)
{
int h = 0;
if (temp != NULL)
{
int l_height = height (temp->left);
int r_height = height (temp->right);
int max_height = max (l_height, r_height);
h = max_height + 1;
}
return h;
}
/*
* Height Difference
*/
int diff(avl_node *temp)
{
int l_height = height (temp->left);
int r_height = height (temp->right);
int b_factor= l_height - r_height;
return b_factor;
}
/*
* Right- Right Rotation
*/
avl_node* rr_rotation(avl_node *parent)
{
avl_node* temp;
temp = parent->right;
parent->right = temp->left;
temp->left = parent;
return temp;
}
/*
* Left- Left Rotation
*/
avl_node* ll_rotation(avl_node *parent)
{
avl_node* temp;
temp = parent->left;
parent->left = temp->right;
temp->right = parent;
return temp;
}
/*
* Left - Right Rotation
*/
avl_node* lr_rotation(avl_node *parent)
{
return parent;
}
/*
* Right- Left Rotation
*/
avl_node* rl_rotation(avl_node *parent)
{
return parent;
}
/*
* Balancing AVL Tree
*/
avl_node* balance(avl_node *temp)
{
int bal_factor = diff (temp);
if (bal_factor > 1)
{
if (diff (temp->left) > 0)
temp = ll_rotation (temp);
else
temp = lr_rotation (temp);
}
else if (bal_factor < -1)
{
if (diff (temp->right) > 0)
temp = rl_rotation (temp);
else
temp = rr_rotation (temp);
}
return temp;
}
/*
* Insert Element into the tree
*/
avl_node* insert(avl_node *root, string value)
{
if (root == NULL)
{
root = new avl_node;
root->data = value;
root->left = NULL;
root->right = NULL;
return root;
}
else if (value < root->data)
{
root->left = insert(root->left, value);
root = balance (root);
}
else if (value >= root->data)
{
root->right = insert(root->right, value);
root = balance (root);
}
return root;
}
avl_node * minValueNode(avl_node* node)
{
avl_node* current = node;
/* loop down to find the leftmost leaf */
while (current->left != NULL)
current = current->left;
return current;
}
bool find(avl_node* root, string data)
{
// STEP 1: PERFORM STANDARD BST DELETE
if (root == NULL)
return false;
// If the data to be deleted is smaller than the
// root's data, then it lies in left subtree
if ( data < root->data ){
return find(root->left, data);
}
// If the data to be deleted is greater than the
// root's data, then it lies in right subtree
else if( data > root->data ){
return find(root->right, data);
}
else
{
return true;
}
}
// Recursive function to delete a node with given data
// from subtree with given root. It returns root of
// the modified subtree.
avl_node* pick(avl_node* root, string data)
{
// STEP 1: PERFORM STANDARD BST DELETE
if (root == NULL)
return root;
// If the data to be deleted is smaller than the
// root's data, then it lies in left subtree
if ( data < root->data )
root->left = pick(root->left, data);
// If the data to be deleted is greater than the
// root's data, then it lies in right subtree
else if( data > root->data )
root->right = pick(root->right, data);
// if data is same as root's data, then This is
// the node to be deleted
else
{
// node with only one child or no child
if( (root->left == NULL) || (root->right == NULL) )
{
avl_node *temp = root->left ? root->left :
root->right;
// No child case
if (temp == NULL)
{
temp = root;
root = NULL;
}
else // One child case
*root = *temp; // Copy the contents of
// the non-empty child
free(temp);
}
else
{
// node with two children: Get the inorder
// successor (smallest in the right subtree)
avl_node* temp = minValueNode(root->right);
// Copy the inorder successor's data to this node
root->data = temp->data;
// Delete the inorder successor
root->right = pick(root->right, temp->data);
}
}
// If the tree had only one node then return
if (root == NULL)
return root;
// STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
//root->height = 1 + max(height(root->left),
// height(root->right));
// STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to
// check whether this node became unbalanced)
balance(root);
return root;
}
void inOrder(avl_node *root){
if(root == NULL){
return;
}
inOrder(root->left);
cout<<root->data<<" ";
inOrder(root->right);
}
};

Binary search tree deletion (C++)

I'm having trouble implementing a binary search tree deletion algorithm on C++. If I try deleting the root, or direct children of the root, it works correctly. But it does not work for deeper levels (just outputs the same tree without any deletion). What is wrong with my code?
typedef struct Node {
int key;
Node *left = NULL;
Node *right = NULL;
} Node;
...
/*
* Delete <key> from BST rooted at <node> and return modified <node>.
*/
Node* BST::pop(Node *node, int key) {
// If <node> is a null pointer, return.
// If <node> doesn't contain the key, traverse down the tree.
// If <node> contains the key, perform deletion.
if (node == NULL) {
} else if (key < node->key) {
node->left = pop(node->left, key);
} else if (key > root->key) {
node->right = pop(node->right, key);
} else {
// If <node> is a leaf, just delete it
if (node->left == NULL && node->right == NULL) {
delete node; // deallocate memory (note: node still points to a memory address!)
node = NULL; // node points to null
}
// If <node> has a single child, replace <node> with its child
else if (node->left == NULL && node->right != NULL) {
Node *tmp = node;
node = node->right;
delete tmp;
tmp = NULL;
} else if (node->right == NULL && node->left != NULL) {
Node *tmp = node;
node = node->left;
delete tmp;
tmp = NULL;
} else {
node->key = findMax(node->left);
node->left = pop(node->left, node->key);
}
}
return node;
}
int BST::findMax(Node *root) {
if (root->left == NULL && root->right == NULL) {
return root->key;
} else {
int max = root->key;
if (root->left != NULL) {
int leftMax = findMax(root->left);
if (leftMax > max) {
max = leftMax;
}
}
if (root->right != NULL) {
int rightMax = findMax(root->right);
if (rightMax > max) {
max = rightMax;
}
}
return max;
}
}
A couple of things:
Second else if should be else if (key > node->key)
Your findMax function is exceptionally complex. The max in a BST from some root is really just traversing right children until there are no more right children (because anything in the left subtree must be less than the key you are currently evaluating, so leftMax can never be > max). Therefore it could be
int BST::findMax(Node *root) {
int max = root->key;
while (root->right != NULL) {
root = root->right;
max = root->key;
}
return max;
}
As long as the tree does not need to remain balanced, your general algorithm of just removing in case of a leaf, swapping the lone child if there is only one, and in the case of two children finding an inorder neighbor, swapping and deleting that node should be sound (not sure if you found this link, but: http://quiz.geeksforgeeks.org/binary-search-tree-set-2-delete/)