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]);.
Related
I have been experimenting with binary trees. I am trying to build an expression tree with the below c++ code. but, i keep getting segmentation fault(core dumped) during runtime
#include<iostream>
#include<ctype.h>
#include<vector>
using namespace std;
struct tree{
char data;
tree *left=NULL;
tree *right=NULL;
tree *parent=NULL;
};
tree* newNode(char d)
{
struct tree* node = new tree;
//struct tree* nodep = &node;
node->data = d;
return node;
}
tree* parseTree(string expression)
{
vector<char> tokens;
for(int i = 0; i<expression.size(); i++)
tokens.push_back(expression[i]);
struct tree* currentNode = newNode(' ');
struct tree* prevNode = new tree;
for(int i = 0; i<tokens.size(); i++)
{
if(tokens[i]=='(')
{
currentNode->left = newNode(' ');
prevNode = currentNode;
currentNode = currentNode->left;
currentNode->parent = prevNode;
}
else if(tokens[i]=='+'||tokens[i]=='-'||tokens[i]=='*'||tokens[i]=='/')
{
currentNode->data = tokens[i];
prevNode = currentNode;
currentNode = currentNode->right;
currentNode->parent = prevNode;
}
else if(isdigit(tokens[i]))
{
currentNode->data = tokens[i];
prevNode = currentNode;
currentNode = currentNode->parent;
}
else if(tokens[i]==')')
{
prevNode = currentNode;
currentNode = currentNode->parent;
}
}
return currentNode;
}
int main()
{
string expression = "(3+(4*5))";
struct tree* root = parseTree(expression);
return 0;
}
I tried different things but i couldn't get rid of this error
what am i missing?
why do i get this error?
how to rectify this?
else if(tokens[i]=='+'||tokens[i]=='-'||tokens[i]=='*'||tokens[i]=='/')
{
currentNode->data = tokens[i];
prevNode = currentNode;
currentNode = currentNode->right;
currentNode->parent = prevNode;
}
No code ever sets any right to anything other than NULL. So in the last line, currentNode is NULL and you are dereferencing a NULL pointer.
Also, take a look here:
struct tree* prevNode = new tree;
This value is never used and when the value is changed, the tree you allocated here is leaked.
This part uses ->right, which was never set:
else if(tokens[i]=='+'||tokens[i]=='-'||tokens[i]=='*'||tokens[i]=='/')
{
currentNode->data = tokens[i];
prevNode = currentNode;
currentNode = currentNode->right;
currentNode->parent = prevNode; // SEGFAULT
}
So you are trying to write to address 0 + some offset, which you are not allowed to.
I am implementing Binary search tree in C++. I have written the following code but for some reason I get an error message that says:
expected a ;
I get above message when compiling the code.
Also I am new to C++ and I would appreciate a lot if I get some help on this one.
Some context to Binary Search Tree:
Binary search trees keep their keys in sorted order, so that lookup
and other operations can use the principle of binary search: when
looking for a key in a tree (or a place to insert a new key), they
traverse the tree from root to leaf, making comparisons to keys stored
in the nodes of the tree and deciding, on the basis of the comparison,
to continue searching in the left or right subtrees. On average, this
means that each comparison allows the operations to skip about half of
the tree, so that each lookup, insertion or deletion takes time
proportional to the logarithm of the number of items stored in the
tree. This is much better than the linear time required to find items
by key in an (unsorted) array, but slower than the corresponding
operations on hash tables.
#include<iostream>
using namespace std;
struct Node
{
int data;
Node *left, *right, *parent;
};
Node* DeleteNode(Node *root, int data);
void find_min(Node *root);
void inorder(Node *x);
void Insert(Node *root, int data);
//delete a node
//search_tree
//insert a node
//temp->parent = NULL;
int main()
{
Node *root, *temp;
//node with 20
temp = new Node;
temp->data = 20;
temp->left = NULL;
temp->right = NULL;
root = temp;
//node with 10
temp = new Node;
temp->data = 10;
temp->left = NULL;
temp->right = NULL;
temp->parent = NULL;
root->left = temp;
temp->parent = root;
//node with 30
temp = new Node;
temp->data = 30;
temp->left = NULL;
temp->right = NULL;
temp->parent = NULL;
root->right = temp;
temp->parent = root;
//node with 25
temp = new Node;
temp->data = 25;
temp->left = NULL;
temp->right = NULL;
temp->parent = NULL;
root->right->left = temp;
temp->parent = root->right;
//node with 40
temp = new Node;
temp->data = 40;
temp->left = NULL;
temp->right = NULL;
temp->parent = NULL;
root->right->right = temp;
temp->parent = root->right;
//node with 2
temp = new Node;
temp->data = 2;
temp->left = NULL;
temp->right = NULL;
temp->parent = NULL;
root->left->left = temp;
temp->parent = root->left;
//node with 15
temp = new Node;
temp->data = 15;
temp->left = NULL;
temp->right = NULL;
temp->parent = NULL;
root->left->right = temp;
temp->parent = root->left;
find_min(root);
cout << "Printing numbers in order" << endl;
inorder(root);
cout << "printing in-order of the given root" << endl;
delete(root);
}
void find_min(Node *root)
{
Node *temp;
temp = root;
while (temp->left != NULL)
temp = temp->left;
cout << "min number is " << temp->data << endl;
}
void inorder(Node *x)
{
if (x != NULL)
{
inorder(x->left);
cout << x->data << endl;
inorder(x->right);
}
}
Node* DeleteNode(Node *root, int data)
{
if (root->data == NULL) {
return root;
}
// If the key to be deleted is smaller than the root's key,
// then it lies in left subtree
else if (data < root->data)
root->left = DeleteNode(root->left, data);
// If the key to be deleted is greater than the root's key,
// then it lies in right subtree
else if (data > root->data)
root->right = DeleteNode(root->right, data);
// case 1: No child
else if (root->left == NULL & root->right == NULL)
delete root;
return root;
//data < root->data struct Node *temp = root;
// case 2: one child
if (root->left == NULL){
Node *temp = root;
root = root->right;
delete temp;
return root;
}
//
else if (root->right == NULL) {
Node *temp = root;
root = root->left;
delete temp;
return root;
}
// case 3: two child
else (root == root->right){
root->data = temp->data;
root->right = DeleteNode(root->right, temp->data);
return root;
}
}
This is your issue: else (root == root->right){. If you want to make that a condition, you'll need to use else if(root == root->right)
Note that per Godbolt, you have more errors even with that fix (they look simple to fix).
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.
I am trying to build a linked list in C++. My understanding is that the code I have created should create a node and then progressively link 4 more onto the end. Unfortunately, while I would expect to see the cout results as "12 123 1234 12345" I'm seeing "12 12 12 12" and in my main I am unable to traverse the list - it just crashes.
I have the following code:
struct listNode {
int val;
listNode* next;
};
int nodeCount = 0;
listNode* addToEnd(listNode* node) {
listNode* newNode = new listNode;
newNode->val = ++nodeCount;
newNode->next = NULL;
if (node == NULL) {
return newNode;
}
listNode* current = node;
cout<<"\n\n";
do {
if (current->next == NULL) {
current->next = newNode;
}
cout<<current->val<<"\n";
current = current->next;
} while (current->next != NULL);
cout<<current->val<<endl;
}
int main()
{
listNode* first = addToEnd(NULL);
addToEnd(first);
addToEnd(first);
addToEnd(first);
addToEnd(first);
cout<<"Third: "<<first->next->next->val;
}
Any help is appreciated, as I am at wit's end!
It is obvious that function addToEnd is wrong
listNode* addToEnd(listNode* node) {
listNode* newNode = new listNode;
newNode->val = ++nodeCount;
newNode->next = NULL;
if (node == NULL) {
return newNode;
}
listNode* current = node;
cout<<"\n\n";
do {
if (current->next == NULL) {
current->next = newNode;
}
cout<<current->val<<"\n";
current = current->next;
} while (current->next != NULL);
cout<<current->val<<endl;
}
Let's assume that the list already contains two nodes and consider the do-while loop inside the function. At first current_next != null so the following statement is executed
current = current->next;
Now current points to the second node. Its data member next is equal to NULL. So the condition of the loop
} while (current->next != NULL);
will be false and no iteration will be repeated. So we added nothing.
Also the function returns nothing if node is not equal to NULL.
Rewrite the function the following way
listNode* addToEnd( listNode* node )
{
listNode* newNode = new listNode { ++nodeCount, NULL };
if ( node == NULL) return newNode;
listNode* current = node;
while ( current->next != NULL ) current = current->next;
current->next = newNode;
return newNode;
// or
//return node;
}
Take into account that this statement
cout<<"Third: "<<first->next->next->val;
outputs only the value of the third node.
If you want to output all the list you should write
for ( listNode *current = first; current; current = current->next )
{
std::cout << current->val << ' ';
}
std::cout << std::endl;
By the way using my function you could write in main for example the following way:)
listNode* first;
addToEnd( addToEnd( addToEnd( addToEnd( first = addToEnd( NULL ) ) ) ) );
Use a for loop to get you to the last node instead of a while, and then assign the new node OUTSIDE of the loop. Trying to do it inside will result in an infinite loop (and make the code harder to read):
listNode* current;
for(current = node; current->next != NULL; current = current->next) ;
current->next = newNode;
You're also forgetting to return newNode at the end of the function.
You're falling off the end of a function with non-void return type. The fact that you don't use the return value does not make that ok.
6.6.3 in the Standard says that:
Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.
There is no return statement just in case the if condition that checks if(node==null) fails..
Is it against the rules to use recursive functions in your question?
Why not do...
void addToEnd(listNode* node){
if(node == NULL){
*node = new listNode;
node->next = NULL;
node->val = ++nodeCount;
}else{
addToEnd(node->next);
}
return;
}
int main(){
listNode* first = NULL;
addToEnd(first); // 1
addToEnd(first); // 2
addToEnd(first); // 3
addToEnd(first); // 4
addToEnd(first); // Linked list is now 5 long
}
This is how I would have coded adding five nodes to a linked list that holds a node count. If anyone has advice it is welcome.
#include <iostream>
#include <cstdlib>
using namespace std;
struct listNode{
int val;
listNode* next;
};
listNode* addToEnd(listNode*, int);
int main()
{
listNode* first = NULL;
listNode* temp;
int nodeCount = 1;
for(int i = 0; i < 5; i++){
first = addToEnd(first, nodeCount);
nodeCount++;
}
temp = first;
while(temp){
cout << temp->val << ' ';
temp = temp->next;
}
temp = first;
//Deallocate memory
while(temp){ //could do memory deallocation while displaying
nodeToDelete = temp; //the value of nodeCount but wanted to illustrate
//both methods individually
temp = temp->next;
delete nodeToDelete;
}
first = NULL; //eliminate hanging pointer
return 0;
}
listNode* addToEnd(listNode* node, int nodeCount)
{
listNode* newNode = new (nothrow) listNode;
listNode* current = node;
if(newNode){
newNode->val = nodeCount;
newNode->next = NULL;
if (node == NULL)
node = newNode;
else{
while (current->next != NULL)
current = current->next;
current->next = newNode;
}
}
else
cout << "error allocationg memory" << endl;
return node;
}
When i write this line: cout<< "LOOK AT HERE PLEASE"; at the function 'insert' the program gives me this output: 1 0 but when erase the line the program gives me this output: 1 2.
Why this is happening?
#include <iostream>
using namespace std;
struct Node{
int data;
Node* next;
};
void initNode(struct Node *head, int n){
head->data = n;
head->next = NULL;
}
void insert(struct Node *head,int n){
Node no;
Node *novo = &no;
novo->data = n;
novo->next = NULL;
Node *cur = head;
while(cur){
if(cur->next == NULL){
cur->next = novo;
return;
}
cout<< "LOOK AT HERE PLEASE";
cur = cur->next;
}
}
void display(struct Node *head){
Node *list = head;
while(list){
cout<<list->data<< " "<<endl;
list = list->next;
}
cout<<endl<<endl;
}
int main(){
Node head;
initNode(&head,1);
insert(&head,2);
display(&head);
}
Change
Node no;
Node *novo = &no;
To
Node *novo = new Node;
Stuff on the stack have short lives.
You then need to figure out how to prevent memory leaks (delete it somewhere!)
What you did in the following code
void insert(struct Node *head,int n){
Node no;
Node *novo = &no;
...
Node *cur = head;
while(cur){
if(cur->next == NULL){
cur->next = novo;
return;
}
is return a pointer to a local variable, which is undefined behavior.
You can fix it, as already pointed out by #ed-heal, by
Node *novo = new Node;
which will allocate a Node dynamically.