So my code is below. I'm not getting any errors and it places everything in the node just fine. But based on my debug statements Everytime anything is inserted it's finding the root. I'm not sure if that is right. But according to output file for the assignment, my answers are different when it comes to the height of the tree, the traversals, and I just flat am still having troubles with my leaf count function. Another story though.
Based on the debug statements it looks like everything is going right where they should. But I figure I might need fresh eyes. I don't see how my traversals could change at all since it is really only a matter of where I'm proccessing the node that should effect the Inorder, preorder, and postorder.
template <class T>
void BT<T>::insert(const T& item)
{
Node<T>* newNode;
newNode = new Node<T>(item);
insert(root, newNode);
}
template <class T>
void BT<T>::insert(struct Node<T> *&root, struct Node<T> *newNode)
{
if (root == NULL)
{
cout << "Root Found" << newNode->data << endl;
root = newNode;
}
else
{
if (newNode->data < root->data)
{
insert(root->left, newNode);
cout << "Inserting Left" << newNode-> data << endl;
}
else
{
insert(root->right, newNode);
cout << "Inserting Right" << newNode->data << endl;
}
}
}
My height function is as follows just in case my insert is actually fine.
template <class T>
int BT<T>::height() const
{
return height(root);
}
template <class T>
int BT<T>::height(Node<T>* root) const
{
if (root == NULL)
return 0;
else
{
if (height(root->right) > height(root->left))
return 1 + height(root-> right);
return 1 + height(root->left);
}
}
You need to change the wording of your debug statements
Really it should read (not Root node)
cout << "Leaf Node Found" << newNode->data << endl;
It is only the root when it is first called after that any call with node->left or node->right makes it an intermediate node.
To write height() I would do this:
template <class T>
int BT<T>::height(Node<T>* root) const
{
if (root == NULL) {return 0;}
return 1 + max(height(root->left),height(root->right));
}
You need to start off with your root init'd to null. Also, you are passing *&node in; it should be *node. Else you're passing a pointer to the address(or reference, I'm not sure which in this context, but both aren't going to be right). You should be passing a pointer to Node in, not a reference.
template <class T>
void BT<T>::BT()
{ root = 0;}
template <class T>
void BT<T>::insert(const T& item)
{
Node<T>* newNode;
newNode = new Node<T>(item);
insert(root, newNode);
}
template <class T>
void BT<T>::insert(struct Node<T> *root, struct Node<T> *newNode)
{
/*stuff*/
}
#Vlion:
It should be a pointer to the left/right/root pointers (i.e. a double pointer), so the posted code is correct, although somewhat unclear.
#Doug:
Consider changing your insert function thus:
template <class T>
void BT<T>::insert(struct Node<T>** root, struct Node<T>* newNode)
{
if (*root == NULL)
{
cout << "Root Found" << newNode->data << endl;
*root = newNode;
}
It makes clear your intention that you'll be changing the pointer passed as the first parameter (or rather, the pointer whose address will be passed as the first parameter.) It will help avoid confusion such as the one that just happened.
The calls to this insert(), such as:
insert(&root, newNode);
will also reflect your intention of changing the pointer's value. This is a matter of style, though, so I can't argue if you don't want to change.
As for checking whether the tree is "correct," why not draw it out and see for yourself? Something along the lines of:
template class<T>
void printTree(struct Node<T>* node, int level=0)
{
if (!node) {
for (int i=0; i<level; ++i)
cout << " ";
cout << "NULL" << endl;
return;
}
printTree(node->left, level+1);
for (int i=0; i<level; ++i)
cout << " ";
cout << node->data << endl;
printTree(node->right, level+1);
}
(Untested code)
Related
I am trying to build a basic Binary search tree in C++ and running into some problems, specifically when I try to insert a node via function and read, it gives me segmentation fault. But the same node struct works perfectly fine when I manually insert it.
The code for BST insert is as follows, and is most likely the culprit:
void BST::insert(Node* temproot,int val){
// std::cout << root->value <<std::endl;
if(!temproot){
Node* newNode = new Node;
newNode->value = val;
temproot = newNode;
std::cout << "Added Node with Value: " << val << std::endl;
return;
}
if(val<(temproot->value)){
std::cout << "LEFT" << std::endl;
insert(temproot->left, val);
}else{
std::cout << "RIGHT" << std::endl;
insert(temproot->right, val);
}
}
The node structure looks like this:
struct Node{
int value;
Node* left = nullptr, *right = nullptr;
};
And the BST class looks something like below:
class BST{
public:
Node* root= new Node;
BST(int val){
root->value = val;
}
void insert(Node*,int val);
void insertStart(int vasl){
Node* temproot = root;
insert(temproot, vasl);
}
void print(Node*);
void _print(){
print(root);
}
};
When I try to print it as follow, it gives me segmentation fault:
void BST::print(Node* temp){
std::cout << temp->value << std::endl;
temp = temp->left;
std::cout << (temp->value) << std::endl;
}
I am a bit new to C++ and am having struggle pin pointing it for couple of days. Can someone help me figure out what I am doing wrong here?
The function deals with a copy of the passed to it pointer to node. So changing a copy does not influence on the original pointer.
You have to pass a pointer to node to the function by reference.
The function declaration can look the following way
void insert(Node* &temproot,int val);
and call it like
void insertStart(int vasl){
insert( root, vasl );
}
without an intermediate pointer.
And you should declare this function as a provate static function of the class.
And initialize the data member root by nullptr.
For example
class BST{
public:
Node* root = nullptr;
BST(int val){
insert( root, val );
}
void insertStart(int vasl){
insert( root, vasl);
}
void print(Node*);
void _print(){
print(root);
}
private:
static void insert(Node* &,int val);
};
Basically, SEGFAULT comes from print function which should look like this:
void BST::print(Node* temp){
if (nullptr == temp) {
return;
}
print(temp->left);
std::cout << temp->value << std::endl;
print(temp->right);
}
And your insert function should look like this:
void BST::insert(Node *&temproot,int val){
if(nullptr == temproot){
Node* newNode = new Node;
newNode->value = val;
temproot = newNode;
return;
}
if(val < (temproot->value)){
insert(temproot->left, val);
}else{
insert(temproot->right, val);
}
}
Check it out live
I'm porting a binary tree implementation from C to C++, converting it to a class in the process.
Sorry in advance for the C way of handling most things.
The attributes consists of
T data;
node<T> *left, *right;
I'm trying to make changes to the root node through
node<T>* current = this; // points to root node
node<T> newnode = node<T>(5); // just a test value
current->left = &newnode;
cout << "current->left: " << current->left << " value: " << current->left->data << endl;
cout << "this->left: " << " value: " << this->left->data << endl;
In my mind, those two prints should print exactly the same thing, since current and this both point to the same object, but the output I got is clearly different
current->left: 0x7fffffffddb0 value: 5
this->left: 0x7fffffffddb0 value: -139656192
So they point to the same left object, but that object holds different values when viewed differently, what gives?
Additoinal Info
Declaration
template <typename T>
class node {
public:
T data;
node<T> *left, *right;
void insert(T data);
int remove(T target); // returns success or not
node<T>* find(T target);
void print(int mode); // need overloading since can't use 'this' as default var
void print(int mode, node<T>* root);
private:
node<T>* node_new(T data);
void node_find(T key, node<T>*** target_node_address_handle);
void node_delete(node<T>** target_address);
};
Constructor
template <typename T>
node<T>::node(T rootdata) {
data = rootdata;
left = NULL;
right = NULL;
}
Find method shared by insert and delete
template <typename T>
void node<T>::node_find(T key, node<T>*** target_node_address_handle) {
node<T>* current = this;
while(current) {
if (typeid(key) == typeid(current->data)) {
if (key == current->data) break;
else if (key < current->data) current = current->left;
else current = current->right;
}
}
// if loop exited without breaking, will insert into empty NULL position
*target_node_address_handle = ¤t;
}
My insert doesn't work, but I'm not sure if that's a problem in node_find or node_insert
template <typename T>
void node<T>::insert(T data) {
node<T>** target_node_address;
node_find(data, &target_node_address);
// target_node_address should now point to one of root's decedents
if (!(*target_node_address)) // nothing at target node as expected
*target_node_address = node_new(data);
// node_new returns pointer to node
}
Edit
Copy constructor
template <typename T>
node<T>::node(const node<T>& anothernode) {
data = anothernode.data;
if(anothernode.left) *left = *anothernode.left;
else left = NULL;
if(anothernode.right) *right = *anothernode.right;
else right = NULL;
}
Destructor (both added in declaration)
template <typename T>
node<T>::~node(void) {
left = NULL;
right = NULL;
}
Interesting thing is that it compiled fine before I explicitly added these in...
Problem solved with new node and insert changed to:
template <typename T>
node<T>* node<T>::node_new(T data) {
node<T>* newnode = new node<T>(data);
return newnode;
}
template <typename T>
void node<T>::node_find(T key, node<T>*** target_node_address_handle) {
// find node matched by key, or NULL pointer in correct location
// give node pointer address back
node<T>* root = this;
node<T>** target_address = &root;
while(*target_address) {
node<T>* current = *target_address;
if(typeid(key) == typeid(current->data)) {
// assume comparison operator exists
if(key == current->data)
break;
else if(key < current->data)
target_address = ¤t->left;
else
target_address = ¤t->right;
}
}
// if loop exited without breaking, will insert into an empty NULL position
// else loop exited by matching/breaking, will delete non-NULL node
*target_node_address_handle = target_address;
}
Problem was I was giving ¤t back to *target_node_address_handle, which would be an address to a pointer to NULL, rather than a pointer to a pointer to NULL, which I could change.
I'm trying to work on a binary search tree data structure, but I cannot seem to accomplish inserting anything into the tree. Every time my program calls the insert function, it believes there is nothing in tree. Here are the 2 classes:
template<typename T>
class TreeNode{
public:
T m_data;
TreeNode* m_right;
TreeNode* m_left;
TreeNode<T>(const T& data, TreeNode<T>* right, TreeNode<T>* left) : m_data(data), m_right(right), m_left(left){};
};
template<typename T>
class MyBSTree : public AbstractBSTree<T>{
protected:
TreeNode<T>* m_root;
int m_size;
And here is the function:
void rec_insert(TreeNode<T>* root, const T& x){
if(root == NULL){
cout << "Inserting here" << endl;
TreeNode<T>* tmp = new TreeNode<T>(x, NULL, NULL);
root = tmp;
}
else if(x < root -> m_data){
cout << "Inserting left" << endl;
rec_insert(root -> m_left, x);
}
else if(x > root -> m_data){
cout << "Inserting right" << endl;
rec_insert(root -> m_right, x);
}
if(root == NULL)
cout << "WHAT IS HAPPENING?" << endl;
cout << "resizing" << endl;
m_size++;
};
The output for inserting a couple of items is this:
Inserting here
resizing
Inserting here
resizing
I really have no clue what is going on here, any help would be greatly appreciated.
You need to do a bit of research on pass by reference and pass by value.
You pass a pointer into your insert method - you can only change the value of root locally - any change you make won't persist beyond the function call. You need to pass by reference to allow root to be changed and see that change outside the rec_insert() method.
Another approach may be to refactor your code to return the root value from rec_insert().
I've been practicing my C++, as it's gotten a little rusty since college, and I'm having a bizarre problem where a member value is being overwritten as soon as my function returns.
template <class T>
class BstNode
{
public:
T value;
BstNode<T>* left;
BstNode<T>* right;
BstNode<T>* parent;
BstNode()
{ left = right = parent = NULL; }
BstNode(T value)
{ this->value=value; left=right=parent=NULL;}
BstNode(T value, BstNode<T>* parent)
{ this->value=value; this->parent=parent; left=right=NULL;}
};
template <class T>
class BinarySearchTree
{
protected:
BstNode<T>* root;
void removeNode(BstNode<T>* node);
void addChild(T value, BstNode<T>* node);
BstNode<T>* find(T value, BstNode<T>* node);
public:
BinarySearchTree()
{ root = NULL; }
~BinarySearchTree()
{ removeNode(root); }
BinarySearchTree<T> insert(T value);
bool contains(T value);
BinarySearchTree<T> remove(T value);
void print();
BstNode<T>* getRoot() {return root;}
};
template <class T>
BinarySearchTree<T> BinarySearchTree<T>::insert(T value)
{
if (root == NULL)
{
root = new BstNode<T>(value);
}
else
{
addChild(value, root);
}
cout << "VAL: " << root->value << endl << "LEFT: " << root->left << endl << "RIGHT: "<< root->right << endl << "ADDR: " << root <<endl;
return *this;
}
template <class T>
void BinarySearchTree<T>::addChild(T value, BstNode<T>* node)
{
if (value > node->value)
{
cout <<"\tgt"<<endl;
if (node->right == NULL)
{
node->right = new BstNode<T>(value, node);
}
else
{
addChild(value, node->right);
}
}
else
{
cout<<"\tlte"<<endl;
if (node->left == NULL)
{
node->left = new BstNode<T>(value, node);
}
else
{
addChild(value, node->left);
}
}
}
// [other member functions]
int main()
{
BinarySearchTree<int> tree;
BstNode<int> *n;
n = tree.getRoot();
cout << "ADDR: " << n <<endl<<endl;
tree.insert(5);
n = tree.getRoot();
cout << "VAL: " << n->value << endl << "LEFT: " << n->left << endl << "RIGHT: "<< n->right << endl << "ADDR: " << n << endl;
return 1;
}
The output of my function is:
$ ./bst
ADDR: 0
VAL: 5
LEFT: 0
RIGHT: 0
ADDR: 0xa917c8
VAL: 11085080
LEFT: 0xa917a8
RIGHT: 0
ADDR: 0xa917c8
I don't understand why the values in the root node changed, but the pointer is still pointing at the same location. The only thing I could think of is that the root node is being created on the stack instead being allocated in the heap, but doesn't new make sure that memory is allocated correctly in C++?
I think the issue is that your insert method returns the BinarySearchTree by value, but you don't have a copy constructor defined. As a result, this makes a shallow copy of the BinarySearchTree, returns it, and causes the copy's destructor to fire. This then deletes the BstNode stored as the root, but since the copied BinarySearchTree shares BstNodes with the original tree, you're trashing memory in the original tree. The error you're getting is from accessing deallocated memory when you try to access the node again.
To fix this, either have the insert function return a reference to the tree (so no copy is made) or define a copy constructor or assignment operator. Ideally, do both. :-)
Hope this helps!
There is something wrong with this C++ code. I've compiled it in VC ++ 6.0. It's giving the error "cannot deduce template argument for type"... The problem is in the display function.
Here's the code:
#include "stdafx.h"
#include <iostream>
#include <conio.h>
using namespace std;
template <class type>
struct one
{
type data;
one *next;
};
one<int> *head, *temp, *mid, *del = NULL;
template <class type>
void athead(type value)
{
one *node = new one;
node->data = value;
node->next = head;
head = node;
}
template <class type>
void add_at_tail(type value)
{
one *node = new one;
node->data = value;
node->next = NULL;
if(head == NULL)
{
head = node;
temp = head;
}
while(temp->next != NULL)
{
temp = temp->next;
}
if(temp != node)
{
temp->next = node;
}
}
template <class type>
void display()
{
one<type> *temp = new one;
temp = head;
cout << "\n\n" << endl;
while(temp != NULL)
{
cout << " " << temp->data << " " << "->";
temp = temp->next;
}
cout << "\n\n\n";
}
int main()
{
int a, b, c;
cout << "Enter the data: " << endl;
cin >> a;
add_at_tail(a);
cout << "Enter the data: " << endl;
cin >> b;
add_at_tail(b);
cout << "Enter the data: " << endl;
cin >> c;
add_at_tail(c);
display();
return 0;
}
Couple problems here, at least:
First, you have defined the template function:
template<class type>
void display()
{
one<type> *temp=new one;
temp=head;
cout<<"\n\n"<<endl;
while(temp!=NULL)
{
cout<<" "<<temp->data<<" "<<"->";
temp=temp->next;
}
cout<<"\n\n\n";
}
This line is malformed, because one is not a complete type (one is a class template)
one<type> *temp=new one;
You need to do this:
one<type> *temp=new one<type>;
Then down in the client code, you attempt to call the function template like this:
display();
But display is a function template with no arguments, so there's no way the compiler can deduce the type of it's template parameter type. You must specify the type of type at the call point.
display<int>();
There are also logic errors with the implementation of display(). You instantiate a single copy of one and don't initialize it. You then try to iterate over it like it's a linked list, but it's not -- its just some uninitialized node you just created. You probably want to pass in the linked list you're trying to iterate over. Something along these lines:
template<class type>
void display(const one<type>& head)
{
one<type> const * temp = &head;
cout<<"\n\n"<<endl;
while(temp!=NULL)
{
cout<<" "<<temp->data<<" "<<"->";
temp=temp->next;
}
cout<<"\n\n\n";
}
Now that display takes parameters mentioned in the template, the compiler is able to deduce its type. You probably want to call it like this:
display(head);
You've got a call to display(), but that's a template function and you've given the compiler no way to deduce the template argument. You can specify it explicitly as display<int>(); (but the code has other problems besides that - you're writing one in a few places, when you should probably be writing one<type>).
Well, since display() takes no arguments, how do you think the compiler can figure out what type you expect type to be reified to? You could give display() a dummy type argument, or, better, move all these methods into a class so the type parameter can be figured out just once for the whole program.
Replacing one *node = new one; with one<type>* node = new one<type>; and altering display(); in main() to display<int>(); fixed all the compiler errors.