I'm trying to create a function that inserts a key struct into a tree. The function sets the root correctly, but does not set the branches when called again with another key. Here is the code:
tree.h:
class tree{
key *tree_root;
public:
tree();
//Constructor
void treedestroy(key *root);
//Tree destructor helper
~tree();
//Destructor
void insert(key* root, key *newkey, int disc);
};
insert function from tree class:
void tree::insert(key *root, key *newkey, int disc){
if (root == NULL){
root = newkey;
return;
}
if (newkey->cord[disc] <= root->cord[disc])
insert(root->left, newkey, (disc+1)%4);
else if (newkey->cord[disc] > root->cord[disc])
insert(root->right, newkey, (disc+1)%4);
}
I'm a little inexperienced with C++ pointers and was wondering how I could fix this code so that it will fill the tree correctly?
I'm not entirely sure about your approach here, but to help get you on your feet, it would help to use a function signature of:
void insert(key*& root, key *newkey, int disc);
This passes the root pointer by reference, which means that changes made inside the function will "stick" to the variable you passed in.
Your function as it stands modifies a function-local variable, without those changes propagating.
This article is a balanced and quick read on passing by reference (I can't say if it's the best - it was just the first decent one I found)
If on the first call newkey is null, root will stay null. Make sure method call is correct.
I would put an else rather than an else if. If it is a binary tree it is either equal, greater, or less than.
Does it get into Insert_helper or not? Why did you not include it, seems important? I would guess it is getting at least that far.
root = newKey;
This do not modify actual root. It just modify function argument which is a copy of pointer you specify when call intsert function.
Correct version would looks something like this:
private:
void tree::insert_helper( key **root, key *newkey, int disc ) {
if ( (*root) == NULL ) {
*root = key;
} else if (newkey->cord[disc] <= root->cord[disc]) {
insert_helper( &((*root)->left), newkey, (disc+1)%4 );
} else {
insert_helper( &((*root)->right), newkey, (disc+1)%4);
}
}
public:
void tree::insert( key *newKey, int disc ) {
insert_helper( &tree_root, newkey, disc );
}
Also you have to be sure that 'key' constructol set NULL for left and right. And tree constructor should set NULL for tree_root
Related
I have a simple question. I have a LinkList class and root is initiated inside the class.
class LinkList {
struct node {
int data;
shared_ptr<node> next;
};
shared_ptr<node> root;
public:
void insert(int data);
void remove(int data);
void print();
int length();
bool search_recursive(int data);
bool search_recursiveUtil(shared_ptr<node> p, int data);
}
Ideally I wanted to implement a recursive function to search for a node. Now I implemented in the following way:
bool LinkList::search_recursiveUtil(shared_ptr<node> p, int data){
if(p == nullptr){
return false;
}
if(p->data == data){
return true;
}
return search_recursiveUtil(p->next, data);
}
bool LinkList::search_recursive(int data){
shared_ptr<node> p = root;
return search_recursiveUtil(p, data);
}
Now clearly you can see that since I do not want root to reach at the end of the linked list as other functions might use this head pointer to do something, I am taking a shared pointer P and traversing it. Now I want to have p to be pass to the "search_recursive" function but since it doesn't take shared_ptr argument so I had to take support of a "search_recursiveUtil" function.
My question is it is right way to approach? How can i implement this without having util function support?
Beside the consideration on why using a recursive search (the will soon result in a stack overflow as soon as the list becomes big enough) instead of a iterating one, since pointers are passed by value, there is no need of p: just call return search_recursiveUtil(root, data). Your reasoning abut root to reach the end of the list is a misconception.
The use of an xUtil function taking a positional parameter not required when calling the search from outside can be a good idea, just make it private to the class, so that -from outside- your interface will be just the search_recursive function.
Also, declare both the functions const, since they are not supposed to modify the data.
An alternative can be place the "Util" function as a node member, so that you can do
bool LinkList::node::search_recursiveUtil(int src_data){
if(data == src_data)
return true;
if(pnext == nullptr)
return false;
return pnext->search_recursiveUtil(src_data);
}
called as
bool LinkList::search_recursive(int data){
root->search_recursiveUtil(data);
}
In principle, that's exactly the way to go:
You have your interface function with the necessary parameters that calls an internal function with the required parameters. This way you keep your root member variable hidden. You could/should even declare your util member function private.
void insert(int key)
{
insertRec(key, root);
}
void insertRec(int key, Node *current)
{
if(current==NULL)
current = new Node(key);
else if(key <= current->value)
insertRec(key, current->leftChild);
else
insertRec(key, current->rightChild);
}
How come this doesn't work?
In the insert function, key value and root of the tree are passed to insertRec. If the node is null, create a new node and set it to the key value. Else, either recursively go left or right until the node hits a null spot and insert a new node there.
It's not true the code 'doesn't work'. Of course it works, just as it is written. The problem is you wrote something different from what you need.
when you pass an argument to insertRec(), the routine gets a copy of a pointer to the Node object. So when you assign a value in
current = new Node(key);
you overwrite a local copy in the local variable current. The calling function (and its data) do not know about it.
If you want the caller to recieve the new value, declare a function takes a reference to a variable:
void insertRec(int key, Node *¤t)
Binary Tree insertion:
#include "stdafx.h"
#include <iostream>
using namespace std;
struct TreeNode {
int value;
TreeNode* left;
TreeNode* right;
};
struct TreeType {
TreeNode* root;
void insert(TreeNode* tree, int item);
void insertItem(int value) {
insert(root, value);
}
};
void TreeType::insert(TreeNode* tree, int number) {
if (tree == NULL) {
tree = new TreeNode;
tree->left = NULL;
tree->right = NULL;
tree->value = number;
cout << "DONE";
} else if (number < tree->value) {
insert(tree->left, number);
} else {
insert(tree->right, number);
}
}
int main() {
TreeType* MyTree = new TreeType;
MyTree->insertItem(8);
return 0;
}
I am currently learning Data structures in C++ and this is the code that make insertion in binary trees.
After it is compiled, everything looks fine, however when i try to execute this program, it crashed.
Can anybody tell me where I am wrong?
In your tree constructor, you need to initialize the root pointer to NULL. It's not guaranteed to be initialized as NULL.
When you compile in linux, you can use gdb to show where the source of the segfault is coming from.
Some other notes:
You should assign the value back to root after you've allocated the new node. You're not doing that because you're missing one of the fundamentals of c++. That is, it's based on c. And the thing about c is that is strictly a "by-value" function/method calling paradigm. So all parameters in a function call are by value. When you pass in the memory address for root, you're actually copying the value of the pointer. Then, you're only updating the local value. You need to assign it back to root. If you'd like to learn that concept front to back, I highly recommend watching Jerry Cain's Programming Paradigms course at Stanford.
In your main function, you should try to keep the symbol names as lower_case instead of CamelCase. This helps differentiate variables from types (types should stay CamelCase).
In your TreeType::insert method, you should call the variable tree_node instead of tree. Doing so helps reflect the correct type and avoids confusion.
Whenever possible, try you use the this->root and this->insert notation. Not only will it correctly resolve if you accidentally create a locally scoped root variable, but it's also clearer to the reader where the data or method is defined. Great coding is about communication. It may only take 100-500ms less for the reader to understand where the symbol points to; however, the tiny savings that you can accumulate in avoiding ambiguities add up into a much clearer piece of software. Your future self (and your colleagues) will thank you. See http://msmvps.com/blogs/jon_skeet/archive/2013/09/21/career-and-skills-advice.aspx
Lastly, I can't overstate enough how important learning from the source is. If you're learning c or c++ for the first time, read http://www.amazon.com/The-Programming-Language-4th-Edition/dp/0321563840 and http://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628. It will save you hours, upon hours, upon hours. After having learned from the source, programming is also A LOT more enjoyable because you understand a good portion of the concepts. And, the truth is, things are more fun when you have a decent level of competence in them.
Try something like this-
struct Node {
int Data;
Node* Left;
Node* Right;
};
Node* Find( Node* node, int value )
{
if( node == NULL )
return NULL;
if( node->Data == value )
return node;
if( node->Data > value )
return Find( node->Left, value );
else
return Find( node->Right, value );
};
void Insert( Node* node, int value )
{
if( node == NULL ) {
node = new Node( value );
return;
}
if( node->Data > value )
Insert( node->Left, value );
else
Insert( node->Right, value );
};
In your TreeType constructor I think you should explicitly make root point to NULL.
TreeType::TreeType() {
root = NULL;
}
I am building a binary search tree. Now I am having a problem with adding a node to the tree.
void BinaryTree::add(int value, Node* node) {
if(!node)
node = new Node(value);
else if(node->key < value)
this->add(value, node->rightNode);
else if(node->key > value)
this->add(value, node->leftNode);
}
This code does not seem to work when I call:
BinaryTree test;
test.add(4, test.root);
test.add(1, test.root);
test.add(5, test.root);
test.add(2, test.root);
test.add(3, test.root);
test.add(7, test.root);
test.add(6, test.root);
After the first add call, the root of the tree 'test' is still empty.
How shall I change the code so that it will be updated when I call add and the node goes to the correct place of the tree?
Thank you very much!
You are passing the Node * by value here:
void BinaryTree::add(int value, Node* node) {
One solution is to pass by reference instead:
void BinaryTree::add(int value, Node *& node) {
^
If you pass by value the function is just receiving a copy of the Node * and so any modification to it will not be reflected back in the calling code.
Also you might want to think about what happens when value is equal to the key.
You recursively call the add function, but nowhere in there do I see you actually assigning leftNode or rightNode to the passed in node.
I am working on some binary tree algorithms and need a "find node with searchindex..." function. The design for treenodes is basically
class TreeNode {
int index; // some identifier
TreeNode *left;
TreeNode *right;
}
and a tree is defined by a pointer to the root-node.
My implementation for the search function is:
void Tree::searchNode(TreeNode * root, int nodeIndex, TreeNode *resultNode){
/* Recursive search */
if (root->index == nodeIndex) {
resultNode = root;
} else {
/* search children if the current node is not a leaf */
if(!root->isLeaf()) {
this->searchNode(root->left,nodeIndex,resultNode);
this->searchNode(root->right,nodeIndex,resultNode);
}
}
}
Arguments: *root is the root-node of the tree, nodeIndex is the search-index and *resultNode is the pointer to the found (or not) node in the tree.
The function does not return a reference or pointer to the found node but modifies the pointer resultNode so it points to the found node. The idea is to initialize resultNode with NULL, perform the search and modify it if a match occurs. Otherwise it remains NULL and I can easily check if there are search results or not.
Another class with a tree buildingTree as member utilizes the search-function in this way:
TreeNode *resultNodePtr = NULL;
this->buildingTree->searchNode(this->buildingTree->rootPtr,
currentNodeIndex, resultNodePtr);
// do sth. with resultNodePtr if != NULL
I create *resultNodePtr on the stack because I just need it temporarily inside the function. Is this done correctly? However: The function does not work. resultNodePtr is always NULL, even if the tree contains a node with the search-index. I debugged it very carefully step by step, it detects
(root->index == nodeIndex)
correctly but
resultNode = root;
does not work (I want resultNode to point to the same adress root points to).
Debugger says resultNode before assignment is 0x0, root node is some adress, after the assignment resultNode remains 0x0.
Do I have to overload the operator= in this case for the class TreeNode?
I have tried it:
TreeNode & TreeNode::operator=(const TreeNode & oldTreeNode){
*this = oldTreeNode;
return *this;
// ignore childs for now
}
I am not an expert but this operator= seems trivial. Does it affect the assignment of two TreeNode pointers *node1 = *node2 at all?
Maybe you can help me. Thanks for reading, appreciate your help.
If I find a solution myself I will post it here.
Regards,
Mark
Because you pass resultNode into the function as a pointer by value, its original value never changes. Think of TreeNode* as literally nothing more than a number representing a memory address; when you reassign it:
resultNode = root;
This modifies the copy that searchNode has, but not the original pointer in the code which invokes searchNode. Take this simpler example:
void Foo(int x)
{
x = 100;
}
void Bar()
{
int x = 0;
Foo(x);
// at this point, x is still 0
}
resultNode's value doesn't change from NULL for the same reason that x doesn't change from 0 when the function Bar is invoked. To fix this issue, pass the pointer in as a pointer to a pointer, or a pointer by reference:
void Tree::searchNode(TreeNode* root, int nodeIndex, TreeNode*& resultNode)
{
// same code
}
... or:
void Tree::searchNode(TreeNode* root, int nodeIndex, TreeNode** resultNodePtr)
{
// assign to *resultNodePtr instead
}
Your resultNode pointer is being passed by value, not by reference. So when the function call completes the pointer on the calling side does not receive a value.
Your algorithm looks fine :)