Sorted Array to BST implementation in C++ - c++

I have the following code that takes in a sorted array of integers and converts it into a balanced binary tree :
class node
{
friend class bst;
public:
node():data(0), left(NULL), right(NULL){}
node(int val): data(val), left(NULL), right(NULL){}
private:
int data;
node* left;
node* right;
};
class bst{
public:
bst():root(NULL){}
bst(node* root):root(root){}
node* sorted_array_to_bst(int arr[], int start, int end)
{
if(start > end) return NULL;
int mid = (start + end)/2;
root = new node(arr[mid]);
root->left = sorted_array_to_bst(arr, start, mid-1);
root->right = sorted_array_to_bst(arr, mid+1, end);
return root;
}
void levelorder(node* root)
{
if(root == NULL) return;
std::queue<node*> Q;
Q.push(root);
while(!Q.empty())
{
node* current = Q.front();
std::cout<<current->data<<" ";
if(current->left) Q.push(current->left);
if(current->right) Q.push(current->right);
Q.pop();
}
}
private:
node* root;
};
int main()
{
int arr[10] = {2,6,7,9,13,15,18,21, 23, 29};
bst* b;
node* r = b->sorted_array_to_bst(arr, 0, 9);
b->levelorder(r);
return 0;
}
The issue is, when I run the program, 29 gets printed infinitely. I think there is something not right with my main function. Any help would be appreciated.

You did not initialized your bst instance b. You just created it without initialization, so when you call:
node* r = b->sorted_array_to_bst(arr, 0, 9);
your code will crash. You should something like this:
bst* b = new b( /* pass a node */ );

Related

Binary Search Tree Deletion Problem When creating the Node class with left node first

I am creating a binary search tree in C++ using classes. When I write the left address first as in the example, deletion is not working correctly for random nodes.
Example:
class Node{
public:
int data;
Node* left;
Node* right;
Node(){ data=0; right=left=NULL;};
Node(int x){ data=x; right=left=NULL;};
bool is_leaf(){ return (left==NULL && right==NULL);
}
};
class BST{
private:
Node* root;
Node * _del(int x,Node* n);
void _insert_rec(int x,Node*n);
public:
BST(){ root=NULL; };
void insert_rec(int x);
void print();
void del(int x);
};
void BST::del(int x)
{
root = _del(x,root);
}
Node * BST::_del(int x,Node* n)
{
if(!n)
return NULL;
else
{
if(x<n->data)
n->left = _del(x,n->left);
else if(x>n->data)
n->right = _del(x,n->right);
else
{
if(n->is_leaf())
{
delete n;
return NULL;
}
else
{
if(!n->right)
{
delete n;
return n->left;
}
else if (!n->left)
{
delete n;
return n->right;
}
else
{
int enb = _max_value(n->left);
n->data = enb;
n->left = _del(enb,n->left);
}
}
}
}
return n;
}
void BST::insert_rec(int x)
{
root = _insert_rec(x,root);
}
Node * BST::_insert_rec(int x,Node* r)
{
if(!r)
return new Node(x);
else
{
if(x>r->data)
r->right = _insert_rec(x,r->right);
else
r->left = _insert_rec(x,r->left);
}
return r;
}
int main(int argc, char** argv)
{
BST *bst = new BST();
bst->insert_rec(50);
bst->insert_rec(100);
bst->insert_rec(20);
bst->insert_rec(10);
bst->insert_rec(70);
bst->print();
bst->del(100);
cout<<endl;
bst->print();
return 0;
}
When I try to delete 100 or 50, the code doesn't work.
If I change the Node class as below everything works fine:
class Node{
public:
int data;
Node* right; // Only changed the order of the addresses.
Node* left;
Node(){ data=0; right=left=NULL;};
Node(int x){ data=x; right=left=NULL;};
bool is_leaf(){ return (left==NULL && right==NULL);
}
};
Changed the order of the addresses. But I want to understand the reason behind this situation.
One problem is here
if(!n->right)
{
delete n;
return n->left;
}
You are deleting the pointer n and then dereferencing it. You should use a temporary variable
if(!n->right)
{
Node* tmp = n->left;
delete n;
return tmp;
}
With that change (in two places) it seems to work for me.

I am not getting how to concatenate two Linked List

I am not getting how to run the concatenate function using both Node and LinkedList as classes. If anyone knows how to do it, please let me know.
Here I have created two classes one for linked list and the former one for Node creation.
Using create function and passing array as Linked list input. Also, I am getting the headref using getHead() and getHead2() functions which give the starting pointer of first and second Linked List respectively.
#include <iostream>
using namespace std;
class Node{
public:
int data;
Node* next;
Node(){
data=0;
next=NULL;
}
Node(int data){
this->data=data;
this->next=NULL;
}
};
class LL{
Node* first, *second;
public:
LL(){
first=second=NULL;
}
void create(int arr[], int n){
Node* t, *last;
first=new Node();
first->data= arr[0];
first->next=NULL;
last=first;
for(int i=1;i<n;i++){
t=new Node();
t->data=arr[i];
t->next=NULL;
last->next=t;
last=t;
}
}
void create2(int arr[], int n){
Node* t, *last;
second=new Node();
second->data= arr[0];
second->next=NULL;
last=second;
for(int i=1;i<n;i++){
t=new Node();
t->data=arr[i];
t->next=NULL;
last->next=t;
last=t;
}
}
Node* getHead(){
return first;
}
Node* getHead2(){
return second;
}
void display(Node* p){
while(p){
cout<<p->data<<" ";
p=p->next;
}
cout<<endl;
}
void concatLL(){
Node* p=first;
while(p->next){
p=p->next;
}
p->next=second;
second=NULL;
}
};
int main()
{
LL l,l2;
int arr[]={1,2,3,4,5,6,7};
int arr2[]={2,5,7,8,9};
int n=sizeof(arr)/sizeof(arr[0]);
int n2=sizeof(arr2)/sizeof(arr2[0]);
l.create(arr,n);
l2.create2(arr2,n2);
cout<<"Displaying first LL"<<endl;
l.display(l.getHead());
cout<<"Displaying second LL"<<endl;
l2.display(l2.getHead2());
cout<<"Displaying Linked list after concatination"<<endl;
l.concatLL();
l.display(l.getHead());
return 0;
}
p is equal to NULL when executing p->next=second; in concatLL() causing undefined behaviour since the while loop runs until p == NULL. You should use while(p->next) instead of while(p) and check that first is not a null pointer before.
A linked list is still a Node, and as others said, at the end of your while loop p is pointed to NULL. You can't NULL->second=second neither NULL=second, so change your while loop stop condition:
void concatLL(){
Node* p=first;
while(p->next){
p=p->next;
}
p->next=second;
second=NULL;
}
};
Here is my solution:
#include <iostream>
using namespace std;
struct Node {
Node* next;
int value;
Node(int value) {
this->value = value;
this->next = NULL;
}
Node(int n, int a[]) {
value = a[0];
next = NULL;
Node* p = this;
for (int i = 1; i < n; i++) {
p->next = new Node(a[i]);
p = p->next;
}
}
void concat(Node* head) {
Node* p = this;
while (p->next != NULL) {
p = p->next;
}
p->next = head;
}
void display() {
Node* current = this;
while (current != nullptr) {
cout << current->value << " ";
current = current->next;
}
cout << endl;
}
};
int main() {
int a[] = { 1, 2, 3, 4, 5 };
int b[] = { 6, 7, 8, 9, 10 };
Node* list1 = new Node(5, a);
Node* list2 = new Node(5, b);
list1->display();
list2->display();
list1->concat(list2);
list1->display();
return 0;
}

How to call a function method recursively in classes in c++?

So, I started learning and reading about OOP not so long ago, I've been implementing all the data structures I know using classes and objects just for overall practice and to get comfortable with using OOP in c++.
I'm implementing the tree data structure and I've been wondering how to call a method recursively(I'm aware that I have to pass in an argument) so that when I create an object in main and call a specific method it's written like the following a.inorder(); and not a.inorder(root) since root is a private attribute.
Is this possible ?
My code:
#include<iostream>
using namespace std;
struct node
{
int data;
node* left;
node* right;
};
class tree
{
private:
node* root;
public:
tree();
tree(int val);
void insert(int val);
void preorder();
void postorder();
void inorder();
int count();
};
tree::tree() : root { NULL }
{
}
tree::tree(int val)
{
root = new node;
root->data = val;
root->left = root->right = NULL;
}
void tree::insert(int val)
{
if (!root)
{
root = new node;
root->data = val;
root->left = root->right = NULL;
}
else
{
node* t = root;
node* p = NULL;
while (t)
{
p = t;
if (val > root->data)
t = root->right;
else
t = root->left;
}
t = new node;
t->data = val;
t->left = t->right = NULL;
if (p->data > t->data)
p->left = t;
else
p->right = t;
}
}
void tree::preorder()
{
if (root)
{
}
}
In your design, a node refers to itself. Since it is the node object that is recursive, you could define the recursive method on node:
struct node
{
int data;
node* left;
node* right;
void preorder() {
//...
left->preorder();
right->preorder();
}
};
And then, tree::preorder() would just dispatch a call to root->preorder().
Write a private static recursive function passing to it the pointer to the root node and call the function from the corresponding public non-static member function.
For example
public:
std::ostream & preorder( std::ostream &os = std::cout ) const
{
return preorder( root, os );
}
//...
private:
static std::ostream & preorder( const node *root, std::ostream &os );
//...
This is a comment rather than an actual answer, as it addresses a different issue than you are asking about. However, it is too long for a comment space, that's why I post it here.
I suppose you erroneously refer to root in this part
while (t)
{
p = t;
if (val > root->data)
t = root->right;
else
t = root->left;
}
IMHO it should look like this:
while (t)
{
p = t;
if (val > t->data)
t = t->right;
else
t = t->left;
}
Also compare the code to seek a place for insert with a code that makes an actual insertion:
if (p->data > t->data)
p->left = t;
else
p->right = t;
You've put a comparison subexpressions in reversed order - when seeking, you test whether the new value is greater than that in an existing node, but when inserting, you test whether the existing value is greater than the new one. If they differ, the code will work OK, because you also swapped left and right in the 'then' and 'else' branch.
However, if the values appear equal, the execution control will go to 'else' in both places. As a result the testing code may stop at empty left pointer, but then a new node would get appended to the right, which was not tested for being NULL.
Why would the tree class do intrinsic operations on node? The node class knows best the node's internal structure, so let it initialize itself. This will also help you to stick to the DRY principle and, indirectly, to the KISS principle, as well as the Single-responsibility principle.
struct node
{
int data;
node* left;
node* right;
node(int val) : data(val), left(NULL), right(NULL) {}
};
class tree
{
private:
node* root;
public:
tree();
tree(int val);
void insert(int val);
};
tree::tree() : root { NULL }
{
}
tree::tree(int val) : root(new node(val))
{
}
void tree::insert(int val)
{
if (!root)
{
root = new node(val);
}
else
{
node* t = root;
node* p = NULL;
while (t)
{
p = t;
if (val < t->data)
t = t->left;
else
t = t->right;
}
t = new node(val);
if (t->data < p->data)
p->left = t;
else
p->right = t;
}
}
Additionally, you can make insert recursive, too.
struct node
{
int data;
node* left;
node* right;
node(int val) : data(val), left(NULL), right(NULL) {}
};
class tree
{
private:
node* root;
public:
tree();
tree(int val);
void insert(int val);
protected:
void insertat(node* p, int val);
};
void tree::insert(int val)
{
if (!root)
root = new node(val);
else
insertat(root, val);
}
void tree::insertat(node* t, int val);
{
if (val < t->data)
{
if (t->left)
insertat(t->left, val);
else
t->left = new node(val);
}
else
{
if (t->right)
insertat(t->right, val);
else
t->right = new node(val);
}
}

Inserting into a Binary Tree (geeksforgeeks) recursively

I'm trying to implement the insertion function used on geeksforgeeks.com but am running into some problems trying to work it into my current code.
I have a vector with the data I need to put into the binary tree. I use this function to pass the numbers into the insertion function:
void populateTree(vector<string> dataVec) {
for (int i = 0; i < dataVec.size(); i++) {
insert(stoi(dataVec[i]), root);
}
}
This is the insertion function:
node* insert(int x, node* node) {
if (node == nullptr)
return newNode(x);
if (x < node->data)
node->left = insert(x, node->left);
else
node->right = insert(x, node->right);
return root;
}
New node function:
node* newNode(int num) {
node* temp = new node;
temp->data = num;
temp->left = temp->right = nullptr;
temp->level = 1;
return temp;
}
Root is a private member within the class which is initialized to nullptr. I'm not sure how I should go about making the first node that comes in from the vector as the root and then keep inserting things beginning from there recursively. Thanks!
The problem in your is related to use of pointer.
Instead of using node* insert(int x, node* node) you should use node* insert(int x, node** node) or node* insert(int x, node*& node) and adopt your code accordingly.
Following is corrected sample code. See it in execution here:
#include <iostream>
#include <vector>
using namespace std;
struct Node
{
int val;
Node* left;
Node* right;
Node(int v)
{
val = v;
left = right = nullptr;
}
};
class Tree
{
Node* root;
Tree()
{
root = nullptr;
}
public:
static void insert(int x, Node*& node)
{
if (node == nullptr)
{
node = new Node(x);
}
else
{
if (x < node->val)
insert(x, node->left);
else
insert(x, node->right);
}
}
static Tree* populateTree(vector<string> dataVec)
{
Tree* t= new Tree();
for (int i = 0; i < dataVec.size(); i++)
{
insert(stoi(dataVec[i]), t->root);
}
return t;
}
static void printTree(Node* node, string s)
{
if(node == nullptr) return;
cout<<s<< "+"<<node->val <<endl;
s += "----";
printTree(node->left,s);
printTree(node->right, s);
}
static void printTree(Tree* t)
{
if(t)
{
printTree(t->root, "");
}
}
};
int main() {
Tree* t = Tree::populateTree({"70", "2", "7", "20", "41", "28", "20", "51", "91"});
Tree::printTree(t);
return 0;
}

can not access memory at address 0xc8

I am writing a code to return data of a node in BST based on id.
below is my node class:
struct Node{
int id;
string data;
Node *left;
Node *right;
Node();
};
below is my node constructor: I defined id and data in addNode function
Node :: Node(){
this->left = nullptr;
this->right = nullptr;
}
below is my BST class:
class BST{
private:
Node * root = nullptr;
void setRoot(Node *);
Node* getRoot();
public:
Node *addNode(BST *, int);//helper function
Node *addNode(Node *,int);
string getEntry(BST*,int);//helper function
string getEntry(Node*,int);
}
below is my helper functions:
Node *BST::addNode(BST *bst, int val){
addNode(bst->getRoot(),val);
}
string BST::getEntry(BST* bst,int id){
getEntry(bst->getRoot(),id);
}
below is my addNode class:
Node* BST::addNode(Node* root, int val) {
Node *newNode = new Node();
newNode->id = val;
newNode->data = "Number " + to_string(val);
if (root == nullptr) {
if (getRoot() == nullptr){
setRoot(newNode);
}
setCount(getCount()+1);
return newNode;
}
if (root->id > val) {
root->left = addNode(root->left, val);
} else {
root->right = addNode(root->right, val);
}
return root;
}
below is my getEntry class:
string BST::getEntry(Node *base,int id) {
if (base == nullptr){
return "";
}
if (base->id == id){
cout<<base->data<<endl;
return base->data;
}
getEntry(base->left,id);
getEntry(base->right,id);
}
below are the nodes I passed in from main:
int main(){
BST *newBst = new BST();
newBst->addNode(newBst,1);
newBst->addNode(newBst,2);
newBst->addNode(newBst,3);
newBst->addNode(newBst,2);
newBst->addNode(newBst,3);
newBst->addNode(newBst,5);
newBst->addNode(newBst,7);
newBst->addNode(newBst,10);
cout<<newBst->getEntry(newBst,5)<<endl;
return 0;
}
The code would compile but does not return anything, I tried to debug, at the "return base->data statement", there is an error "can not access memory at address 0xc8". What causes the problem and what can I do about it?
this is the warning I got when I debug the code.
if (base->id != id){
getEntry(base->left,id);
getEntry(base->right,id);
}
As you are using a sorted tree, you know which of the right or left node you need to have a look at. Also, you need to return something:
if (base->id > val){
return getEntry(base->left,id);
}
return getEntry(base->right,id);
But the design with addNode is very bad, you shouldn't have to pass the root twice!