friends. So I'm creating a Binary Search Tree Class in ubuntu using vim as my editor, and when I run my program I always get a segmentation fault(core dumped) error. The weird thing is that when I run this program on NetBeans, it worked perfectly. this is my code
#include <iostream>
using namespace std;
class BST
{
struct node {
int data;
node* left;
node* right;
};
private:
node* root;
node* addHelper(node* temp, int data)
{
if(temp == NULL)
{
temp = new node;
temp->left = temp->right = NULL;
temp->data = data;
return temp;
}
if(data < temp->data)
{
temp->left = addHelper(temp->left, data);
}
else if(data > temp->data)
{
temp->right = addHelper(temp->right, data);
}
return temp;
}
void printHelper(node* cur)
{
if(cur == NULL)
{
return;
}
else {
printHelper(cur->left);
cout << cur->data << " ";
printHelper(cur->right);
}
}
public:
void add(int value)
{
root = addHelper(root, value);
}
void printInorder()
{
printHelper(root);
}
};
int main()
{
cout << "Second Test, linux runnning sucsesfully"<<endl;
BST mytree;
mytree.add(20);
mytree.add(25);
mytree.add(10);
mytree.add(22);
mytree.add(15);
mytree.add(12);
mytree.add(23);
mytree.printInorder();
return 0;
}
I already use gdb to debug, and it pointed me an error on the printHelper function but I can't see the error. if you know how to fix this please help me.
thank you in advance
Certianly yes the problem is the data member root is used and not initialized
Solution for the problem
public:
BST(){
root = new node();
}
If at all the use case demands some more operations in the constructor you can also use the initializer list which is good in terms of readability. Just an add-on you should always initialize const and reference using the initializer list.
Or using the initializer list
public:
BST(node* root):root(root){
//Any other initialization /Operation
}
Or give it a NULL (or nullptr, in the most recent C++ standard).
public:
BST() : root(NULL) { }
Our default ctor here makes it NULL (replace with nullptr if needed), the second constructor will initialize it with the value passed..
You don't initialize your root variable before using it. You can initialize it in a constructor as the following:
public:
BST(){
root = new node();
}
The fix is just initialize the root as NULL . [Do not allocate anything there.]
constructor must be like below
BST() {
root = NULL;
}
Also root shall be created only once We should not be change it ever. So change the code like below
if (root == NULL) {
root = addHelper(root, value);
} else {
addHelper(root, value);
}
Related
I have implemented binary search tree in C++ and for some reason I am not seeing where the segmentation fault occurs. But I do notice that when I comment out root = node in the first conditional statement in addNode the error goes away. What exactly is a segmentation fault and how does it related to pointers?
#include <iostream>
#include <iomanip>
using namespace std;
class bstNode
{
public:
int value;
bstNode *left;
bstNode *right;
bstNode(){};
~bstNode(){};
bstNode(int value)
{
this->value = value;
this->left = NULL;
this->right = NULL;
}
bstNode(int value, bstNode *left, bstNode *right)
{
this->value = value;
this->left = left;
this->right = right;
}
bstNode *root;
void addNode(int value)
{
if (root == NULL)
{
bstNode *node = new bstNode(value);
root = node;
}
else
{
bstNode *focusNode = root;
bstNode *parent;
while (focusNode != NULL)
{
if (value > focusNode->value)
{
focusNode = focusNode->right;
if (focusNode == NULL)
{
focusNode->right = new bstNode(value);
}
}
else
{
focusNode = focusNode->left;
if (focusNode == NULL)
{
focusNode->left = new bstNode(value);
}
}
}
}
}
static void printBST(bstNode *node)
{
while (node != NULL)
{
printBST(node->left);
cout << node->value;
printBST(node->right);
}
}
};
int main()
{
bstNode *node = new bstNode();
node->addNode(7);
node->addNode(2);
node->addNode(18);
node->addNode(6);
node->addNode(4);
node->addNode(23);
bstNode::printBST(node->root);
return 0;
}
The immediate error is this
if (focusNode == NULL) {
focusNode->left = new bstNode(value);
}
this is clearly wrong, if a pointer is null you cannot use it. You have this in multiple places. Fix that and then update the question once you have got past that. How did I know this? I ran your code under my debugger and it told me immediatley, you should learn how to get the most out of your debugger.
Next
void addNode(int value)
as a method for a class defined as
class bstNode {
public:
int value;
is very bad practice. In that method what does value refer to? The argument or the member variable. Get into the habit of giving member variables specific names like this
class bstNode {
public:
int value_;
Also minor nits. The accepted style for naming classes is with leading Caps like this
class BstNode {
public:
int value_;
or even
class BSTNode
class bstNode {
public:
int value_;
using namespace std;
I'd advise against doing this in general. It's hard to be sure what's in namespace std, but the short summary is "a lot, and more all the time", so making all of it visible directly can lead to problems.
bstNode(){};
~bstNode(){};
These don't really accomplish anything useful. The point of a constructor is to initialize the object, but these just leave the object uninitialized, which can lead to problems--especially segmentation faults when/if you try to dereference an uninitialized pointer.
bstNode(int value){
this->value = value;
this->left = NULL;
this->right = NULL;
}
This is better, but I'd prefer to use a member initializer list instead of assignments inside the body of the ctor, and I'd prefer nullptr over NULL:
bstNode(int value)
: value(value)
, left(nullptr)
, right(nullptr) {}
This next one:
bstNode(int value, bstNode* left, bstNode* right){
this->value = value;
this->left = left;
this->right = right;
}
...is pretty nicely written (though it could also use a member initializer list, which is usually preferable), but only rarely useful when building a binary search tree, because in normal use you only ever insert new leaf nodes, not new internal nodes.
void addNode(int value){
if (root == NULL){
bstNode* node = new bstNode(value);
root = node;
}
else{
bstNode* focusNode = root;
bstNode* parent;
while(focusNode != NULL){
if(value > focusNode->value){
focusNode = focusNode->right;
if(focusNode == NULL){
focusNode->right = new bstNode(value);
}
}
else{
focusNode = focusNode->left;
if(focusNode == NULL){
focusNode->left = new bstNode(value);
}
}
}
}
}
This is at least one obvious source of a segmentation fault--you dereference a pointer immediately after verifying that it's null.
At least for a first attempt, I think I'd use a recursive implementation, which tends to be simpler:
void addNode(int value, bstNode *&node = root) {
if (node == nullptr) {
node = new node(value);
} else if (value < node->value) {
addNode(value, node->left);
} else if (value > node->value) {
addNode(value, node->right);
} else {
// attempt at inserting duplicate value
}
}
Note that this passes a reference to a pointer, so we can modify the "current" pointer, rather than having to track the parent pointer while traversing the tree.
static void printBST(bstNode* node){
while(node != NULL){
printBST(node->left);
cout << node->value;
printBST(node->right);
}
}
Since we're doing this recursively, we don't need (or even want) a loop. Traversing the left sub-tree, the current node, and the right subtree traverses the entire tree, with no iteration needed.
Also note that this doesn't print any delimiter between the numbers in the nodes, so a tree containing 12, 34 and a tree containing 1, 2, 3, 4 will both be printed out as 1234, which probably isn't very useful. Fortunately, adding a delimiter is pretty easy.
static void printBST(bstNode* node){
if (node != nullptr){
printBST(node->left);
cout << node->value << ' ';
printBST(node->right);
}
}
In the the following code...
while(focusNode != NULL){
if(value > focusNode->value){
focusNode = focusNode->right;
if(focusNode == NULL){
focusNode->right = new bstNode(value);
}
}
else{
focusNode = focusNode->left;
if(focusNode == NULL){
focusNode->left = new bstNode(value);
}
}
}
...you are referencing the children of a node that is guaranteed to be NULL because you verified that using the conditional statement. Since the node itself does not exist, it doesn't have properties like children. Imagine you're trying to communicate with the child of a person who has never existed.
The variable focusNode stores an address of a node. What focusNode->value does is that it goes to the node whose address focusNode stores and retrieves the value property from there.
When focusNode is NULL, it doesn't point to any node, thus you can't go there and retrieve its value property.
I wrote the code that you can replace with your while loop. I have tested it and it works:
while(true){
if(value > focusNode->value){
if(focusNode->right == NULL){
focusNode->right = new bstNode(value);
return;
} else focusNode = focusNode->right;
}
else{
if(focusNode->left == NULL){
focusNode->left = new bstNode(value);
return;
} else focusNode = focusNode->left;
}
}
I also fixed your printBST function. In the printBST function use if instead of while, because the the code inside the while loop would be executed an infinite number of times instead of printing the BST once.
static void printBST(bstNode* node){
if(node != NULL){
printBST(node->left);
cout << node->value <<" ";
printBST(node->right);
}
}
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 ...*/
}
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node *left, *right;
Node()
{
data = NULL;
left = right = NULL;
}
};
Node* insertBST(Node* root, int value)
{
if (root == NULL) {
root->data = value;
root->left = root->right = NULL;
}
if ((root->data) > value)
insertBST(root->left, value);
if ((root->data) < value)
insertBST(root->right, value);
}
Node* printBST(Node* root)
{
if (root != NULL) {
printBST(root->left);
cout << "\n" << root->data;
printBST(root->right);
}
}
int main()
{
Node* root = new Node;
insertBST(root, 30);
insertBST(root, 20);
insertBST(root, 40);
insertBST(root, 70);
insertBST(root, 60);
insertBST(root, 80);
printBST(root);
}
Above is the code which I wrote to implement Binary Search Tree. When I execute it, the program stops responding and closes. I tried getting help from pythontutor.com but I am not able to tackle it.What should I do to make it run without error?
here is where it stops : Click to see
Any help is appreciated,I am new to writing program.
In insertBST in the case of root == NULL you do not create a new node and attempt to modify the contents of root, as this is null it should result in an access violation or segmentation fault.
I think the reason your program is hanging instead of crashing is that you are using an online compiler that ignores invalid writes and instead allows the program to continue. This then possibly ends up with infinite recursion through the insertBST function.
To fix this you need to allocate a new node, one way would be as follows:
void insertBST(Node*& root, int value)
{
if (root == NULL) {
root = new Node();
root->data = value;
root->left = root->right = NULL;
}
if ((root->data) > value)
insertBST(root->left, value);
if ((root->data) < value)
insertBST(root->right, value);
}
Note that your program leaks all the nodes that it allocates. You should write a destructor in Node which deletes all child nodes and call delete root at the end of your program. Alternatively don't use raw pointers at all and use std::shared_ptr or std::unique_ptr instead.
struct Tnode {
Tnode *left;
Tnode *right;
int content;
Tnode (int item = 0) {
this->content = item;
left = nullptr;
right = nullptr;
}};
class KrTree {
private:
Tnode* root;
void printHelper (Tnode* root) {
if(!root) {
return;
}
printHelper(root->left);
cout << root->content << " ";
printHelper(root->right);
}
void addHelper (Tnode *root, int item) {
if (root->content < item) {
if (root->right) {
addHelper(root->right, item);
} else {
root->right = new Tnode (item);
}
}else {
if (root->left) {
addHelper(root->left, item);
} else {
root->left = new Tnode (item);
}
}
}
public:
// KrTree (){
// }
void addTreeNode (int item) {
if (root){
this->addHelper(root, item);
} else {
root = new Tnode(item);
}
}
void tnodes_count () {
}
void deleteTreeNode () {
}
void printTree () {
printHelper (this->root);
}
//~KrTree (){}};
Above I've implented a binary search tree. please note i have commented my c-tor and d-tor. My problem is above code works good but give segmentation fault when i enable my c-tor and d-tor.
Here is client code:
KrTree* tree = new KrTree();
tree->printTree();
tree->addTreeNode(7);
tree->addTreeNode(2);
tree->addTreeNode(10);
tree->addTreeNode(1);
tree->addTreeNode(5);
tree->addTreeNode(9);
tree->addTreeNode(20);
tree->printTree();
I know that i am missing something very silly here. please let me know whey enabling my c-tor and d-tor gives segmentation fault
As per my comment...
From the code shown a default constructed KrTree has an uninitialized root member. What you're seeing is simply undefined behaviour.
Without constructor KrTree.root is initialized by default 0 value. With constructor, well, it doesn't happen. Then addTreeNode tries to use this value as reference and segmentation fault happens. Default values in debug mode in Visual Studio are something like 0xcdcdcdcdcdcdcdcd. You can debug application up to first addTreeNode and see actual value for root.
To fix this you should promptly initialize member variable value in constructor. For example:
KrTree () : root(nullptr) {
}
This is my first time working with trees. I wrote a c++ code, but it says Segmentation fault (core dumped) , As far as I searched, this error comes from accessing a memory location that may be NULL. I tried 'new' keyword as malloc() should be avoided in c++, But still I didn't get how to resolve this in my code.
# include<iostream>
using namespace std;
struct node
{
int data;
node *left;
node *right;
}*next;
int k=0;
void tree(int i,/*struct*/ node *next = new node)
{
++k; --i;
if (i==0)
return;
//next = new node;
next->data = k*k;
next->left = NULL;
next->right = NULL;
tree(i, next->left);
tree(i, next->right);
return ;
}
void display (node* next)
{
cout<<next->data<<" ";
if (next->left!=NULL)
{
display(next->left);
display(next->right);
}
}
int main()
{
int h;
cout<<"Enter the expected height of tree : ";
cin>>h;
node *root;
root = new node;
root->data=0;
root->left=NULL;
root->right=NULL;
tree(h, (root->left));
tree(h, (root->right));
cout<<root->data<<" ";
display(root->left);
display(root->right);
return 0;
}
There are serious problems with this code. In particular, here:
void display (node* next)
{
cout<<next->data<<" ";
if (next->left!=NULL)
{
...
}
}
You dereference next without ever checking to see whether it's null. And it will be null. That's enough to explain the error you see.
I say that it will be null because of this:
void tree(int i,/*struct*/ node *next = new node)
{
...
return ;
}
...
root->left=NULL;
...
tree(h, (root->left));
...
display(root->left);
The tree function takes its second argument by value-- that means that it does not change the value of root->left. You then call display with a null argument. I suspect that you think void tree(int i,/*struct*/ node *next = new node) means something other than what it actually means.
More fundamentally, you must review the two ways to pass an argument, by reference and by value.
More fundamentally still, you must start with a small, simple program and build up in small steps, rather than trying to write a big complex program all at once.
#include <iostream>
using namespace std;
struct node
{
int data;
struct node *left;
struct node *right;
};
void tree(int i, struct node **root, int k)
{
if (i < 1)
return;
*root = new struct node;
(*root)->data = k*k;
(*root)->left = NULL;
(*root)->right = NULL;
tree(i - 1, &((*root)->left), k + 1);
tree(i - 1, &((*root)->right), k + 1);
}
void display(struct node *root)
{
if (root == NULL)
return;
cout << root->data << " ";
if (root->left != NULL)
display(root->left);
if (root->right != NULL)
display(root->right);
}
int main()
{
struct node *root;
int h;
cout<<"Enter the expected height of tree : ";
cin>>h;
tree(h, &root, 0);
display(root);
return 0;
}
I think you should do some more read up on how pointers works: http://www.tutorialspoint.com/cprogramming/c_pointers.htm
When you where calling tree(h, root->left) you actually just send the pointers value "NULL" == 0x0. As you want to allocate memory for it you should send a reference to the pointer. Hence &root and &((*root)->left). In the display function you have to check for NULL values both for left and right.
The code above is only improved and doesn't handle any freeing of memory, to be able to do that, traverse the tree and use delete on all leafs and work you back to the root.