Hi guys I have a doubt in inserting a new node in BST. In the addNode module I am trying to insert an element in the BST, but each time while adding a new node it is adding to the same root node which I passed from main function initially without traversing inside the tree.
This is the code which I have written.
#include<stdio.h>
#include<stdlib.h>
#include<cstdio>
#include<iostream>
using namespace std;
struct node
{
int data;
struct node *left;
struct node *right;
};
struct node* newNode(int data)
{
node* temp = (node*)malloc(sizeof(struct node));
//struct temp = new node;
temp->data = data;
temp->left = NULL;
temp->right = NULL;
return(temp);
};
int addNode(node *dest, node *root)
{
if(root == NULL)
{
cout<<"adding data to node for "<< dest->data<<endl;
root = dest;
cout<<"ROOT VALUE = root->data "<<root->data<<endl;
return 1;
}
if(dest->data > root->data)
{
cout<<"Traverse right for "<<dest->data<<endl;
addNode(dest, root->right);
}
else if(dest->data < root->data)
{
cout<<"Traverse left for "<<dest->data<<endl;
addNode(dest, root->left);
}
}
void printNodes(node *root)
{
if(root != NULL)
{
printNodes(root->left);
if(root->left != NULL && root->right != NULL)
std::cout<< root->data <<" ";
printNodes(root->right);
}
}
int main()
{
int i, j, k, flag;
int arr[6] = {4, 2,8, 1, 0, 10};
node *start = newNode(arr[0]);
for(i = 1; i < 6; i++)
{
node *newOne = newNode(0);
newOne->data = arr[i];
cout<<"NODE DATA - start->data "<<start->data;
if(addNode(newOne, start))
std::cout<<"\nNode added"<<endl;
}
printNodes(start);
return 1;
}
I am quite new to trees concept as well as pointers concept in trees. Any help is appreciated and thank you.
... but each time while adding a new node it is adding to the same root
node
This is because you are adding it always to the same root, as here
if(addNode(newOne, start))
start is always the same. You could make addNode return the new root and call it like that:
start = addNode(newOne,start);
I'll leave it to you to implement it.
Note that parameters are always passed by value in c++ (unless you pass-by-reference), thus changing the parameter inside the method, root = dest;, has no effect on the start in main.
Related
I am working on a BST and when I print out the elements in any order, I get a random '0' appended to it, but I cannot find where its coming from.
I followed the pseudo code thats present in Introduction to algorithms by Cormen and have also looked at Geeks for Geeks but I have no luck getting rid of that 0.
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node* LeftChild;
Node* RightChild;
Node(int data){
this->data = data;
this->LeftChild = NULL;
this->RightChild = NULL;
}
//pointers of the class
};
class BST {
private:
Node* root;
public:
BST(){ ///creating an empty tree in Constant Time
root = new Node(NULL);
}
Node* getRoot(){ return this->root; };
int i =0;
void printTree(Node *root)
{
if (root == NULL)
return;
else {
printTree(root->LeftChild);
cout << root->data << " ";
printTree(root->RightChild);
}
}
Node* InsertNode(Node *root,int data)
{
Node *z = new Node(data);
Node *y = new Node(NULL);
Node *x = this->root;
//if(x->data < z->data){
// x = z;
//return x;
//}
while(x!= NULL){
y = x;
if(data < x->data){
x = x->LeftChild;
}
else{
x = x->RightChild;
}
}
if(y== NULL) y= z;
else if(data < y->data){
y->LeftChild = z;
}
else{
y->RightChild =z;
}
return y;
/*
if(this->root->data== NULL){
this->root =z;
return root;
}
else{
this->root =y;
}
*/
//this->root = z;
//return root;
}
bool FindNode(Node *root,int data);
int Largest(Node *root){
return root->data;
}
};
int main()
{
BST myBst;
Node * root = (myBst.getRoot());
root = myBst.InsertNode(root, 24);
myBst.InsertNode(root, 60);
myBst.InsertNode(root, 55);
myBst.InsertNode(root, 32);
myBst.printTree(root);
return 0;
}
Here is the output:
0, 24,32,55,60
The constructor does not make a sense
BST(){ ///creating an empty tree in Constant Time
root = new Node(NULL);
}
There is created a dummy node with initialization of the data member data with NULL.
What you need is just to write
BST() : root( nullptr ) { ///creating an empty tree in Constant Time
}
The function InsertNode must have only one parameter instead of two parameters as you wrote
Node* InsertNode(Node *root,int data){
The pointer root is the data member of the class. So there is no need to pass it to the function. Otherwise the function should be declared as a static member function of the class (that nevertheless does not make a great sense).
That is the function should be declared like
void InsertNode( int data ){
Also the function has at least a memory leak
Node* InsertNode(Node *root,int data){
Node *z = new Node(data);
Node *y = new Node(NULL);
Node *x = this->root;
while(x!= NULL){
y = x;
//...
The function can be written for example the following way
void InsertNode( int data )
{
Node *new_node = Node( data );
Node **current = &root;
while ( *current != nullptr )
{
if ( data < ( *current )->data )
{
current = &( *current )->LeftChild;
}
else
{
current = &( *current )->RightChild;
}
}
*current = new_node;
}
I wanted to implement a BST class with a vector and somehow its not working. I just wanted to know the reason why its not working.
The main reason that I can think of that root in the BST always remain NULL.
I wanted to experiment ways to use classes in data structures.
#include<iostream>
#include<vector>
using namespace std;
class Node{
public:
int data;
Node* left ;
Node* right ;
Node(int val){
data = val;
left = NULL;
right = NULL;
}
};
class BST{
public:
Node* root = NULL;
void insert(Node* r,int data){
Node* new_node = new Node(data);
if(r == NULL){
r = new_node;
}
if(data < r->data){
if(r->left == NULL){
r->left = new_node;
}
else{
insert(r->left,data);
}
}else if(data > r->data){
if(r->right == NULL){
r->right = new_node;
}
else{
insert(r->right,data);
}
}else{
return;
}
return;
}
BST(vector<int> bst_array){
for(int i = 0; i<bst_array.size(); i++){
insert(root,bst_array[i]);
}
}
void print_t(Node* r){
if(r == NULL){
cout<<"NULL";
return;
}
else{
print_t(r->left);
cout<<r->data<<" ";
print_t(r->right);
}
}
};
int main(){
vector<int> v = {1,3,5,44,23,78,21};
BST* tr = new BST(v);
tr->print_t(tr->root);
return 0;
}
There seem to be a logical mistake on my end please help me find it.
Thanks in advance.
The reason is that root is never assigned another value after its initialisation to NULL. Passing root as argument to the insert method can never alter root itself, as it is not the address of root that is passed, but its value.
Some other remarks:
insert always starts by creating a new node, at every step of the recursion. This is a waste of node creation. In the end you just need one new node, so only create it when its position in the tree has been identified.
The final else is not needed, as all it does is execute a return, which it would have done anyway without that else block
As insert is a method of BST, it is a pity that it requires a node as argument. You would really like to just do insert(data) and let it take care of it. For that to happen I suggest to move your insert method to the Node class, where the this node takes over the role of the argument. Then the BST class could get a wrapping insert method that forwards the job to the other insert method.
Instead of NULL use nullptr.
To solve the main issue, there are many solutions possible. But after making the above changes, it is quite easy to assign to root in the simplified insert method on the BST class.
Here is how it could work:
class Node{
public:
int data;
Node* left ;
Node* right ;
Node(int val){
data = val;
left = nullptr;
right = nullptr;
}
void insert(int data) {
if (data < this->data) {
if (this->left == nullptr) {
this->left = new Node(data);
} else {
this->left->insert(data);
}
} else if (data > this->data) {
if (this->right == nullptr) {
this->right = new Node(data);
} else {
this->right->insert(data);
}
}
}
};
class BST {
public:
Node* root = nullptr;
void insert(int data) {
if (root == NULL) { // Assign to root
root = new Node(data);
} else { // Defer the task to the Node class
root->insert(data);
}
}
BST(vector<int> bst_array){
for(int i = 0; i<bst_array.size(); i++){
insert(bst_array[i]); // No node argument
}
}
/* ...other methods ...*/
}
I am confused a bit. I narrowed down it to:
Why having this line:
Node *root, *rootSafe = NULL;
give error:
Segmentation fault(core dumped)
While just switching it like below:
Node *rootSafe, *root = NULL;
runs perfect.
Here is the code, you can test.
#include <iostream>
using namespace std;
struct Node{
int data;
Node *left, *right;
Node(int d){
this->data = d;
this->left = this->right = NULL;
}
};
Node *newNode(int d){
Node *temp = (Node *)malloc(sizeof(Node));
temp->data = d;
temp->left = temp->right = NULL;
return temp;
}
void printInorder(Node *root){
if(root == NULL){
return;
}
else{
printInorder(root->left);
cout << "--" << root->data;
printInorder(root->right);
}
}
int main()
{
//cout << "Hello World";
Node *rootSafe, *root = NULL;
int arr[] = {5, 3, 1, 4, 6};
int sizeArr = sizeof(arr)/sizeof(arr[0]);
for(auto i = 0; i < sizeArr; i++){
if(root == NULL){
rootSafe = newNode(arr[i]);
root = rootSafe;
}
else{
while(root != NULL){
if(arr[i] < root->data){//Move left
if(root->left == NULL){
root->left = newNode(arr[i]);
root = NULL;
}
else{
root = root->left;
}
}
else{//Move right
if(root->right == NULL){
root->right = newNode(arr[i]);
root = NULL;
}
else{
root = root->right;
}
}
}
}
root = rootSafe;
}
cout << "\n Print Inorder: ----"; printInorder(rootSafe);
return 0;
}
Without fiddling with your code, I think this:
Node *root, *rootSafe = NULL;
Doesn't do what you think it does. Do you think it sets both to NULL? It doesn't. root gets some random value and rootSafe gets NULL.
This might be what you really want:
Node *root = NULL, *rootSafe = NULL;
Frankly, I personally hate (and it's against coding conventions at some work places) specifying multiple variables on the same line. You will not find this in my code. Instead, you will see:
Node * root = nullptr;
Node * rootSafe = nullptr;
Note also that in modern C++, NULL is not a pointer. Get in the habit of using nullptr.
You are using root here:
if(root == NULL){
Your original declaration
Node *root, *rootSafe = NULL;
doesn't initialize root, leaving it with indeterminate value. Therefore, root with some random invalid value may be dereferenced and it may lead to Segmentation Fault.
To avoid this, you should initialize root before using that.
It can be done in declaration:
Node *root = NULL, *rootSafe = NULL;
Or before the loop:
root = NULL;
for(auto i = 0; i < sizeArr; i++){
Node *root, *rootSafe = NULL;
Node *rootSafe, *root = NULL;
The first line leaves root uninitialized. This causes undefined behaviour while access root.
The second line leaves rootSafe uninitialized but the var later initialized rootSafe = newNode(arr[i]);.
If I need to print out each elements of a binary tree constructed with the struct below. How could I keep track of which layer of elements I am printing?
struct for a binary tree node
For example:
any binary tree
Expected output:
layer 0: 12
layer -1: 28 19
layer -2: 94 32
layer -3: 65 18 72
Solution using queue based on GeeksForGeeks
#include <iostream>
#include <queue>
using namespace std;
// A Binary Tree Node
struct node
{
struct node *left;
int data;
struct node *right;
};
// Iterative method to do level order traversal
// line by line
void printLevelOrder(node *root)
{
// Base Case
if (root == NULL)
return;
// Create an empty queue for level order tarversal
queue<node *> q;
// Enqueue Root and initialize height
q.push(root);
int i = 0;
while (q.empty() == false)
{
cout << "layer " << i << ": ";
// nodeCount (queue size) indicates number
// of nodes at current lelvel.
int nodeCount = q.size();
// Dequeue all nodes of current level and
// Enqueue all nodes of next level
while (nodeCount > 0)
{
node *node = q.front();
cout << node->data << " ";
q.pop();
if (node->left != NULL)
q.push(node->left);
if (node->right != NULL)
q.push(node->right);
nodeCount--;
}
cout << endl;
--i;
}
}
// Utility function to create a new tree node
node *newNode(int data)
{
node *temp = new node;
temp->data = data;
temp->left = NULL;
temp->right = NULL;
return temp;
}
// Driver program to test above functions
int main()
{
// Create binary tree
node *root = newNode(12);
root->left = newNode(28);
root->right = newNode(19);
root->left->left = newNode(94);
root->left->left->left = newNode(65);
root->left->left->right = newNode(18);
root->right->left = newNode(32);
root->right->left->right = newNode(72);
printLevelOrder(root);
return 0;
}
Solution using recursive function and helper function based on CrazyForCode:
#include <iostream>
using namespace std;
struct node
{
int data;
struct node *left;
struct node *right;
};
void printLevel(node *, int);
int height(struct node *node);
/* Function to print level order traversal a tree*/
void printLevelOrder(struct node *root)
{
int h = height(root);
int i;
for (i = 1; i <= h; i++){
printf("layer %d: ",i*-1+1);
printLevel(root, i);
cout << endl;
}
}
/* Print nodes at a given level */
void printLevel(struct node *root, int level)
{
if (root == NULL)
return;
if (level == 1)
{
printf("%d ", root->data);
}
else if (level > 1)
{
printLevel(root->left, level - 1);
printLevel(root->right, level - 1);
}
}
/* Compute the "height" of a tree */
int height(struct node *node)
{
if (node == NULL)
return 0;
else
{
int lheight = height(node->left);
int rheight = height(node->right);
if (lheight > rheight)
return (lheight + 1);
else
return (rheight + 1);
}
}
node *newNode(int data)
{
node *temp = new node;
temp->data = data;
temp->left = NULL;
temp->right = NULL;
return temp;
}
int main()
{
// Create binary tree
node *root = newNode(12);
root->left = newNode(28);
root->right = newNode(19);
root->left->left = newNode(94);
root->left->left->left = newNode(65);
root->left->left->right = newNode(18);
root->right->left = newNode(32);
root->right->left->right = newNode(72);
printLevelOrder(root);
return 0;
}
typedef struct treeNode {
treeNode* left;
treeNode* right;
int data;
treeNode(int d) {
data = d;
left = NULL;
right = NULL;
}
}treeNode;
void insert(treeNode *root, int data) {
if (root == NULL) {
cout << &root;
root = new treeNode(data);
}
else if (data < root->data) {
insert(root->left, data);
}
else {
insert(root->right, data);
}
}
void inorderTraversal(treeNode* root) {
if (root == NULL)
return;
inorderTraversal(root->left);
cout<<root->data;
inorderTraversal(root->right);
}
int main() {
treeNode *root = new treeNode(1);
cout << &root << endl;
insert(root, 2);
inorderTraversal(root);
return 0;
}
So I'm pretty tired, but I was whipping some practice questions up for interview prep and for some reason this BST insert is not printing out that any node was added to the tree. Its probably something im glossing over with the pointers, but I can't figure it out. any ideas?
void insert(treeNode *root, int data) {
if (root == NULL) {
cout << &root;
root = new treeNode(data);
}
This change to root is lost as soon as the function ends, it does not modify the root passed as argument but its own copy of it.
Take note that when u insert the node, use pointer to pointer (pointer alone is not enough):
So, here is the fixed code:
void insert(treeNode **root, int data) {
if (*root == NULL) {
cout << root;
*root = new treeNode(data);
}
else if (data < (*root)->data) {
insert(&(*root)->left, data);
}
else {
insert(&(*root)->right, data);
}
}
And in main:
int main() {
treeNode *root = new treeNode(1);
cout << &root << endl;
insert(&root, 2);
inorderTraversal(root);
return 0;
}
Your logic is correct!
The only issue is that when you create a local variable, even if it is a pointer, its scope is local to the function. In your main:
...
insert(root, 2);
...
function call sends a copy of the root which is a pointer to treeNode (not the address of root). Please note that
void insert(treeNode *root, int data)
gets a treeNode pointer as an argument (not the address of the pointer). Attention: This function call may look like "call by pointer" (or reference) but it is actually "call by value". The root you define in the main function and the root inside the insert method have different addresses in the stack (memory) since they are different variables. The former is in main function stack in the memory while the latter is in insert method. Therefore once the function call insert finishes executing, its stack is emptied including the local variable root. For more details on memory refer to: stacks/heaps.
Of course the data in the memory that you allocated using:
*root = new treeNode(data);
still stays in the heap but you have lost the reference to (address of) it once you are out of the insert function.
The solution is either passing the address of original root to the function and modifying it (as K-ballo and dip has suggested) OR returning the modified local root from the function. For the first approach please refer to the code written by dip in his/her answer.
I personally prefer returning the modified root from the function since I find it more convenient especially when implementing other common BST algorithms. Here is your function with a slight modification of your original code:
treeNode* insert(treeNode *root, int data) {
if (root == NULL) {
root = new treeNode(data);
}
else if (data < root->data) {
root->left=insert(root->left, data);
}
else {
root->right=insert(root->right, data);
}
return treeNode;
}
The function call in main will be:
int main() {
treeNode *root = new treeNode(1);
cout << &root << endl;
root = insert(root, 2);
inorderTraversal(root);
return 0;
}
Hope that helps!
After a while seeing some complicated methods of dealing with the Binary tree i wrote a simple program that can create, insert and search a node i hope it will be usefull
/*-----------------------Tree.h-----------------------*/
#include <iostream>
#include <queue>
struct Node
{
int data;
Node * left;
Node * right;
};
// create a node with input data and return the reference of the node just created
Node* CreateNode(int data);
// insert a node with input data based on the root node as origin
void InsertNode (Node* root, int data);
// search a node with specific data based on the root node as origin
Node* SearchNode(Node* root, int data);
here we define the node structure and the functions mentioned above
/*----------------------Tree.cpp--------------*/
#include "Tree.h"
Node* CreateNode(int _data)
{
Node* node = new Node();
node->data=_data;
node->left=nullptr;
node->right=nullptr;
return node;
}
void InsertNode(Node* root, int _data)
{
// create the node to insert
Node* nodeToInsert = CreateNode(_data);
// we use a queue to go through the tree
std::queue<Node*> q;
q.push(root);
while(!q.empty())
{
Node* temp = q.front();
q.pop();
//left check
if(temp->left==nullptr)
{
temp->left=nodeToInsert;
return;
}
else
{
q.push(temp->left);
}
//right check
if(temp->right==nullptr)
{
temp->right=nodeToInsert;
return;
}
else
{
q.push(temp->right);
}
}
}
Node* SearchNode(Node* root, int _data)
{
if(root==nullptr)
return nullptr;
std::queue<Node*> q;
Node* nodeToFound = nullptr;
q.push(root);
while(!q.empty())
{
Node* temp = q.front();
q.pop();
if(temp->data==_data) nodeToFound = temp;
if(temp->left!=nullptr) q.push(temp->left);
if(temp->right!=nullptr) q.push(temp->right);
}
return nodeToFound;
}
int main()
{
// Node * root = CreateNode(1);
// root->left = CreateNode(2);
// root->left->left = CreateNode(3);
// root->left->left->right = CreateNode(5);
// root->right = CreateNode(4);
// Node * node = new Node();
// node = SearchNode(root,3);
// std::cout<<node->right->data<<std::endl;
return 0;
}