C++ Binary Tree Path finding - c++

I have a question regarding finding sum of a path of a binary int tree. This is for college so the requirements are as follows:
Take your code from Lab Sheet 3B (Binary Tree) for a binary tree of integers, and code a
method called hasPathSum() which given a binary tree and a sum, return true if the tree
has a root-to-leaf path such that adding up all the values along the path equals the given
sum. Return false if no such path can be found. The function prototype is
int hasPathSum(struct node* node, int sum)
Note: a "root-to-leaf path" is a sequence of nodes in a tree starting with the root node
and proceeding downward to a leaf (a node with no children). An empty tree contains
no root-to-leaf paths. So for example, the following tree has exactly four root-to-leaf
paths:
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
Root-to-leaf paths:
path 1: 5 4 11 7
path 2: 5 4 11 2
path 3: 5 8 13
path 4: 5 8 4 1
For this problem, we will be concerned with the sum of the values of such a path -- for
example, the sum of the values on the 5-4-11-7 path is 5 + 4 + 11 + 7 = 27.
I am having trouble with this. I have a binary tree, but the function hasPathSum() requirs to pass a node, not a tree. I canot figure out how to do this. I also don't know how to find the sum of a path from root to leaf (the hasPathSum body as well). This needs to be done recursively.
Any help is greatly appreciated.
Here is my node class:
#include <stdio.h>
#pragma once
struct TreeNode
{
public:
friend class BinaryTree;
TreeNode(int theData) : data(theData) {}
bool isLeaf();
private:
int data;
TreeNode *leftlink;
TreeNode *rightLink;
};
Here is the BinaryTree header file:
#include "TreeNode.h"
#include <stdio.h>
#include <algorithm>
#include <iostream>
using namespace std;
#pragma once
class BinaryTree
{
public:
BinaryTree();
void add(int toadd);
int height();
void inorderShow() const;
int hasPathSum(TreeNode * tree, int sum);
private:
void add(TreeNode *toAdd, TreeNode *& addHere);
int height(TreeNode *& root);
TreeNode *root;
void inorderShow(TreeNode *subTree) const;
};
And my BinaryTree cpp file:
#include "BinaryTree.h"
BinaryTree::BinaryTree()
{
}
void BinaryTree::add(int toAdd)
{
TreeNode *node = new TreeNode(toAdd);
add(node, root);
}
int BinaryTree::height()
{
return height(root);
}
void BinaryTree::add(TreeNode * toAdd, TreeNode *& addHere)
{
if (addHere == NULL)
addHere = toAdd;
else if (toAdd->data < addHere->data)
add(toAdd, addHere->leftlink);
else //toAdd->data >= addHere->data
add(toAdd, addHere->rightLink);
}
int BinaryTree::height(TreeNode *& n)
{
if (n == NULL)
return -1;
else
return 1 + max(height(n->leftlink), height(n->rightLink));
}
void BinaryTree::inorderShow(TreeNode * subTree) const
{
if (subTree != NULL)
{
inorderShow(subTree->leftlink);
cout << subTree->data << " ";
inorderShow(subTree->rightLink);
}
}
void BinaryTree::inorderShow() const
{
inorderShow(root);
}
int BinaryTree::hasPathSum(TreeNode * tree, int sum)
{
}
In the main.cpp, I have a tree as follows:
#include <iostream>
#include "BinaryTree.h"
#include "TreeNode.h"
using namespace std;
int main()
{
BinaryTree tree;
tree.add(5);
tree.add(6);
tree.add(3);
tree.add(4);
tree.add(9);
tree.add(11);
cout << "Height of the tree is: ";
cout << tree.height() << " ";
cout << "\nIn Order Show:" << endl;
tree.inorderShow();
cout << "Root to leaft path: " << endl;
cout << endl;
system("pause");
return 0;
}
Is someone could explain how can I accomplish this task and meet the requirements (aka not change the function hasPathSum() parameters) I would really appreciate that.

Seems to me the requirement is wrong (or maybe confused)
and code a method called hasPathSum() which given a binary tree and a
sum
So given that this is a method of the binary tree class the tree is passed implicitly so the only explicit parameter is the sum. So the method should be declared as
class BinaryTree
{
...
bool hasPathSum(int sum);
...
};
However the given signature is
int hasPathSum(struct node* node, int sum)
which has the wrong return type (int not bool) and an unexplained node parameter.
Here's how I would organise the solution, since it involves two methods, it maybe explains the confusion.
class BinaryTree
{
...
public:
bool hasPathSum(int sum) { return hasPathSumHelper(root, sum); }
...
private:
static bool hasPathSumHelper(TreeNode* node, int sum);
};
The public hasPathSum method has the signature implied by the problem description (the only signature that makes sense). It simply calls a private method hasPathSumHelper passing the root node and the sum, this gets round the problem of how you pass the private root node.
The hasPathSumHelper method is the recursive routine where the real work is done (left for you to implement). The public hasPathSum just kicks off the calculation by calling this method.
As you think about how to implement the hasPathSumHelper you might find it useful to add additional parameters (a sum_so_far parameter which, as you descend the tree, is the sum of all the nodes above you makes sense to me). That's OK because it's a private method, you can add what you like.

Related

Traversing general nodes class, listing all nodes results in a infinite loop

I am practicing traversing trees/nodes and i came to the current problem. I want to be able to connect one node to itself. Connect node 1 to node 2. Nodes can be connected to as many nodes as desirable. This is the current class that i wrote and practicing with.
My problem is that i cannot check if i already traversed a past node. What i get is an infinite loop of one -> two -> three -> four -> one -> two ... and so on.
Would be possible to be given a tip to the right direction?
I want nodeN.list_connections() to be able to print all nodes that nodeN connects to.
class Node {
private:
std::vector<Node*> nodes;
std::string data;
public:
Node()
{
printf("Status: Created [%d]\n", this);
}
void connect(Node& node)
{
nodes.push_back(&node);
printf("Status: Node [%d] Connected To [%d]\n", this, &node);
}
void input_data(std::string str_in)
{
data = str_in;
}
void list_connections()
{
printf("List: Start\n");
printf("Node[this][%d]: %s\n", this, data.c_str());
for (size_t i = 0; i < nodes.size(); i++)
{
printf("Node[i=%d][%d]: %s\n", i, nodes[i], nodes[i]->data.c_str());
if (this != nodes[i])
nodes[i]->list_connections();
}
}
};
void test_list()
{
Node one;
one.input_data("ONE");
Node two;
two.input_data("TWO");
Node three;
three.input_data("THREE");
Node four;
four.input_data("FOUR");
// one -> two <-> three -> four -> one
// one -> one
// two -> two
one.connect(two);
one.connect(one);
two.connect(two);
two.connect(three);
three.connect(four);
four.connect(one);
three.connect(two);
one.list_connections();
//two.list_connections();
//three.list_connections();
//four.list_connections();
}
This is my code above.
My test_list function tests all possible connection scenarios.
EDIT:
The current idea of my nodeOne.list_connections(), is that it will loop through all the nodes connected to nodeOne. Those nodes will also use nodeOther.list_connections() only if the current node is not connected to other node.
EDIT:
All the nodes are connected in some way. When listing the connections it will only list connections from that node down. Listing nodes will not go back to the root/first node.
EDIT:
by using only one.list_connections(); the output should be
List: Start
Node[this][7731340]: ONE
Node[i=0][7731288]: TWO
Node[i=1][7731340]: ONE
List: Start
Node[this][7731288]: TWO
Node[i=0][7731288]: TWO
Node[i=1][7731236]: THREE
List: Start
Node[this][7731236]: THREE
Node[i=0][7731184]: FOUR
Node[i=1][7731288]: TWO
List: Start
Node[this][7731184]: FOUR
Node[i=0][7731340]: ONE
Thank you StephanH for pointing it out.
You have to tackle a common place problem (avoid cycles) in graph theory. You may create a simple Path class to track if a node was already/or is currently printed in the current recursion stack. Therefore, you have to check if the new node is already in the recursion stack. Let's use the standard std::find() applied to an integer vector storing node ids. For readability and easier useage I wrapped it in bool Path::closeCycle(int nid). Since a path could consist at most of |N| elements the Path class could also represented by a n-dimensional vector<bool> which would avoid using std::find(). This could increase performance, but this perhaps depends on the structure of your graph (long paths+few nodes vs. short paths+hugh amount of nodes vs. something between vs. extrems).
In node.h
#include <cstdlib>
#include <string>
#include <vector>
#include <algorithm>
class Path
{
std::vector<int> vals;
public:
Path();
bool closeCycle(int nid)const;
void add(int nid);
};
class Node {
private:
int id;
std::vector<Node*> nodes;
std::string data;
public:
Node(int id) : id(id)
{
printf("Status: Created [%d]\n", this);
}
void connect(Node& node)
{
nodes.push_back(&node);
printf("Status: Node [%d] Connected To [%d]\n", this, &node);
}
void input_data(std::string str_in)
{
data = str_in;
}
void list_connections(const Path& path = Path());
inline int getId()const { return id; }
};
In node.cpp
#include "header.h"
void Node::list_connections(const Path& path)
{
printf("List: Start\n");
printf("Node[this][%d]: %s\n", this, data.c_str());
Path npath(path);
npath.add(id);
for (size_t i = 0; i < nodes.size(); i++)
{
if (!npath.closeCycle(nodes[i]->id))
{
printf("Node[i=%d][%d]: %s\n", i, nodes[i], nodes[i]->data.c_str());
nodes[i]->list_connections(npath);
}
}
printf("List: %s End\n", data.c_str());
}
Path::Path()
{
}
bool Path::closeCycle(int nid) const
{
return std::find(vals.begin(), vals.end(), nid) != vals.end();
}
void Path::add(int nid)
{
vals.push_back(nid);
}
Your main.cpp
void main()
{
Node one(1);
one.input_data("ONE");
Node two(2);
two.input_data("TWO");
Node three(3);
three.input_data("THREE");
Node four(4);
four.input_data("FOUR");
one.connect(two);
one.connect(one);
two.connect(two);
two.connect(three);
three.connect(four);
four.connect(one);
three.connect(two);
one.list_connections();
std::cout << "\n\n";
two.list_connections();
std::cout << "\n\n";
three.list_connections();
std::cout << "\n\n";
four.list_connections();
std::cout << "\n\n";
system("pause");
}

geany returning strange results in the basis for my binary search tree results C++

I began to write a project today to learn more about binary search trees but while writing the class definitions and checking them my accessor was returning false
results returning 2 and then on the next line 4196704 in the terminal.
heres the code:
#include <iostream>
using namespace std;
class node
{private:
int data;
node *right,*left;
public:
node();
node(int d,node *r,node *l)
{
d= data;
r=right;
l=left;
}
int nodedata() ;
};
int node::nodedata()
{
return data;
}
int main()
{
node root(30,0,0);
node root2(77,0,0);
cout<< root.nodedata() << endl;
cout<< root2.nodedata() << endl;
return 0;
}
You are not writing c++ much I guess.
your definition of variable is wrong:
d= data;
should be
data = d;
And as for why it shows some werid data in output, those are digits in the actual memory location that your system has put there before you assign this chunck of memory, which you have not yet rewrite, to this object,
and for assigning pointers:
r=right;
l=left;
should be
right= r;
left=l;
and if you wanna access them, put them public or create method to access it
eg:
cout<<(root.right)-> nodedata() << endl; //if you make right && left public

C++ executable crashing [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am starting to create a binary tree. So far all I have added is an insert function and I believe it works fine. When I compile my application, header and implementation files together it produces a executable but with an error code above it about exception handler used.... When I go to run the executable it crashes. I don't understand why it is crashing, can someone please help! Thanks in advance.
The command line errors http://gyazo.com/7ca1e8fb1a66da39e927e9ba627d3f53
My application file called mainprogramming.cpp
#include <iostream>
#include <cstdlib>
#include "Header.h"
using namespace std;
int main()
{
int Rndnums[10] = {3, 99, 76, 49, 32, 9, 77, 64, 81, 24};
BinaryTree *tree = new BinaryTree();
for(int i = 0; i < 10; i++)
{
tree->insert(Rndnums[i]);
}
return 0;
}
My header file called Header.h
class BinaryTree
{
// Can only be accessed by the class itself
private:
struct node
{
// Data stored in this node of he tree
int data;
// The left branch of the tree
node *left;
// The right branch of the tree
node *right;
};
node *tree;
void insert(node *tree, int value);
// Can be accessed by all
public:
BinaryTree(){};
~BinaryTree();
void insert(int value);
};
My implementation file called implementation.cpp
#include <iostream>
#include <cstdlib>
#include "Header.h"
using namespace std;
// Inserts a value into the tree - notice **
void BinaryTree::insert(node *tree, int value)
{
// Check if nullptr. If so set new node
if (tree == nullptr)
{
// Create new node
tree = new node;
// Set new value
tree->data = value;
// Set branches to nullptr
tree->left = nullptr;
tree->right = nullptr;
}
// If the input value is less than the node in the tree
else if(value < tree->data)
{
insert(tree->left, value);
cout << "The value " << value << "has been added as a left child\n";
}
// If the input value is greater than the node in the tree
else if(value > tree->data)
{
insert(tree->right, value);
cout << "The value " << value << "has been added as a right child\n";
}
else
{
cout << "The value " << value << "can only be equal and must already exist in the tree\n";
}
}
void BinaryTree::insert(int value)
{
insert(this->tree, value);
cout << "It ran";
}
Your problem is in your insert call:
void BinaryTree::insert(node * leaf_head, int value)
{
...
}
You are copying the pointer address then trying to create an object in that memory space, and then modifying that object. It works fine when you change it to a reference to that pointer:
void BinaryTree::insert(node * & leaf_head, int value)
{
...
}
That way you are actually modifying the tree pointer within BinaryTree instead of a copy of it.

Storing data in the nodes of a Binary Tree

I'm creating some basic AI for Tic-Tac-Toe in C++. It involves creating a Binary Tree that consists of a 'board' class. Each node randomly places a X or O and then creates two more children until someone has won or the game has been drawn. To keep track of the value of each node, I use an integer: -1 for O winning, 0 for draw, 1 for X winning and 2 for game still in progress. Here is an example of what a game could look like.
After my tree has been populated, I will need to look through the left and right side of the root node and sum up all the leafs. The side with the higher sum will be the more desirable option of the initial two children.
I have some very rough code for the expansion of the tree that appears to work, however, when I attempt to sum up my tree after its expansion, I seem to have lost the value that each node contains. Here is my .cpp for the node
BTNode.cpp
#include <iostream>
#include <string>
#include "BTNode.h"
#include <ctime>
#include <cstdlib>
#include <iostream>
using namespace std;
BTNode::BTNode(board gameboard, string setplayer)
{
value = 2; //assume the game is continuing
cout << "Beginning a new node\n";
nodeboard = gameboard;
player = setplayer;
expand();
}
void BTNode::expand()
{
//place a piece
cout << "Expanding";
placerandom(player);
//check to see if a leaf
value = nodeboard.checkwinner(); //returns -1 for O win, 0 for draw, 1 for X win and 2 for game still in progress
cout << "Value of this node: " << value << "\n";
if (value == 2)
{
if (player == "X")
{
BTNode right(nodeboard, "O");
BTNode left(nodeboard, "O");
}
else
{
BTNode left(nodeboard, "X");
BTNode right(nodeboard, "X");
}
}
else
{
cout << "A game had ended";
}
}
int BTNode::getvalue(int side)
{
//in case this node is the root, i will only want to check 1 side of the tree
//-1 is left side, 0 is both, 1 is right
int toreturn=0;
if (value ==2)
{
if (side == -1)
{
toreturn = left ->getvalue(0);
}
if (side == 0)
{
toreturn = right->getvalue(0) + left->getvalue(0);
}
if (side == 1)
{
toreturn = right->getvalue(0);
}
}
else
{
cout << "\nThis is a leaf, returning: " << value;
toreturn = value;
}
return toreturn;
}
void BTNode::placerandom(string player)
{
srand(time(NULL)); //make a new seed based off time
int randx = rand()%3;
int randy = rand()%3;
while (not nodeboard.place(randx,randy,player))
{
randx = rand()%3;
randy = rand()%3;
}
nodeboard.printboard();
}
BTNode.h
#include <string>
#include "board.h"
using namespace std;
class BTNode
{
public:
BTNode(board gameboard, string setplayer);
void placerandom(string player);
int getvalue(int side);
void expand();
private:
board nodeboard;
string player;
BTNode *left;
BTNode *right;
int value;
};
In theory, I should just be able to call "root -> getvalue(-1)" from the tree, which would return a summation of all the nodes beginning from the left side of the tree. However, attempting to get 'value' from any nodes after the expansion functions returns "-1131609994".
Have I created my tree wrong? It seemed quite promising until I attempted to sum it.

File I/O in C++ - Having some trouble writing back data?

This project is a basic ATM program. I'm using a file to store all the account details. So, every time I run the .exe file, It will read the data from the file and insert it into an AVL tree. And when I close the program, all the data in the AVL nodes will be inserted back into the file.
Data is stored in the file in this order (Each separated by a newline char) ID, Password, Name, Add, City, Pin, Balance.
Sample file --
12
4576
Vert
No_999,GoLane
Dallas
89777
50000
16
2342
Nerd
No_888,FoLane
Chicago
89999
30000
The problem is I cannot write back data into the file. Any suggestions please?
P.S. Please excuse my inline class methods please...
Program--
#include<iostream>
#include<conio.h>
#include<string.h>
#include<fstream>
using namespace std;
fstream file("one2.txt",ios::in|ios::out);//Opening the file 'one2.txt' in global scope
//AVL tree code starts here
class avl
{
struct node //The structure node which is going to hold the data sets in the tree
{
int id,pwd;
char name[15],add[30],city[10];
int pn;
double bal;
node *left, *right;
int height;
//node constructors
node(int i,int p,char nam[15], char a[30], char c[10],int pin,double b, node * l,node * r,int h)
{
id=i;
pwd=p;
strcpy(name,nam);
strcpy(add,a);
strcpy(city,c);
pn=pin;
bal=b;
left=l;
right=r;
height=h;
}
node()
{
left=right=NULL;
id=pwd=pn=0;
bal=0;
height=-1;
}
};
node *root;
node *nullnode;
int Height(node *t)const //Func to return the height of a node
{
return((t==NULL)? -1:t->height);
}
int max(int a,int b)
{
return(a>b)?a:b;
}
//Beginning of Insert() -- To create and insert data into the nodes
void insert(const int &x,int p, char nam[15], char a[30], char c[10],int pin,double b, node *&t)
{
if(t==NULL)
t = new node(x,p,nam,a,c,pin,b,NULL,NULL,-1);
else if(x<t->id)
{
insert(x,p,nam,a,c,pin,b,t->left);
if(Height(t->left) - Height(t->right)==2)
{
if(x<t->left->id)
single_rotate_with_left(t);
else
double_rotate_with_left(t);
}
}
else if(x>t->id)
{
insert(x,p,nam,a,c,pin,b,t->right);
if(Height(t->right)-Height(t->left)==2)
{
if(x>t->right->id)
single_rotate_with_right(t);
else
double_rotate_with_right(t);
}
}
else
t->height=max(Height(t->left),Height(t->right)+1);
}
//End of insert()
//Func to print the node data. Just a sample to check if all the data
// were inserted into the tree
//Inorder traversal
void print(node *&t)
{
if(t!=NULL)
{
print(t->left);
cout<<endl;
cout<<"ID "<<t->id<<" Name "<<t->name;
cout<<endl<<t->pwd<<endl<<t->add<<"\n"<<t->city;
cout<<"-"<<t->pn<<endl<<t->bal<<endl;
print(t->right);
}
}
//Think there's gonna be no problem with the rotation and other AVL tree func codes.
//Beginning of AVL rotations
void single_rotate_with_left(node *&k2)
{
node *k1=k2->left;
k2->left=k1->right;
k1->right=k2;
k2->height=max(Height(k2->right),Height(k2->left))+1;
k1->height=max(Height(k1->left),(k2->height))+1;
k1=k2;
}
void single_rotate_with_right(node *&k2)
{
node *k1=k2->right;
k2->right=k1->left;
k1->left=k2;
k2->height=max(Height(k2->left),Height(k2->right))+1;
k1->height=max(Height(k1->right),(k2->height))+1;
k1=k2;
}
void double_rotate_with_left(node *&a)
{
single_rotate_with_right(a->left);
single_rotate_with_left(a);
}
void double_rotate_with_right(node *&a)
{
single_rotate_with_left(a->right);
single_rotate_with_right(a);
}
//End of AVL rotations
//Function to return the node. The 'id' variable to be searched is passed as a param
node*& search(int x,node *&t)
{
if(t->id>x)
return search(x,t->left);
else if(t->id<x)
return search(x,t->right);
else if(t->id==x)
{
return t;
}
else
return nullnode;
}
//End of search. I'm using this in the loadnode() function.
//This is where I try to write data back into the file.
void update1(node *&t,int x) // x is the control variable
{
if(x==1)
//This block will be executed only once when the function is called for the
//first time. Used to seek to the beginning of the file
{
file.seekg(0,ios::beg);
x++;
}
if(t!=NULL)// Inorder traversal in the tree
{
update1(t->left,x);
//writing the data in the same order as it was stored.
file<<t->id<<endl;
file<<t->pwd<<endl;
file<<t->name<<endl;
file<<t->add<<endl;
file<<t->city<<endl;
file<<t->pn<<endl;
file<<t->bal<<endl;
update1(t->right,x);
}
}
public:
//Avl Constructor - This one is the one which is actually used.
avl(int x,int p,char nam[15], char a[30], char c[10],int pin,double b)
{
root= new node(x,p,nam,a,c,pin,b,NULL,NULL,-1);
nullnode=new node;
}
avl()
{
root->left=root->right=NULL;
root->height=-1;
}
//Call to the private insert function
void insert1(const int &x,int p,char nam[15], char a[30], char c[10],int pin,double b)
{
insert(x,p,nam,a,c,pin,b,root);
}
//Call to the private print() function
void display()
{
cout<<endl;
print(root);
}
//Function to write a new value for 'bal' variable to a node.
//I'm actually using this to update a node anconfirm whether the value of the updated node
//is reflected back at the node
void loadnode(int x)
{
node *&t=search(x,root);
cout<<"\nLoaded node...\n";
cout<<t->id;
cout<<" "<<t->name;
t->bal=40000;
cout<<"\nUpdated Bal.."<<t->bal;
}
void update()
{
//file.seekp(0);
update1(root,1);
}
};//End of AVL Class
main()
{
cout<<"The output..\n";
int i, p, pn;
char n[15],a[30],c[10];
double b;
int prev_id=0;
file>>i>>p>>n>>a>>c>>pn>>b;
prev_id=i;
avl list(i,p,n,a,c,pn,b);
while(file)
{
file>>i>>p>>n>>a>>c>>pn>>b;
if(prev_id!=i)
// I'm using this because i got a weird scenario in which the last record was repeated twice.
{
list.insert1(i,p,n,a,c,pn,b);
}
prev_id=i;
}
cout<<endl<<"The elements in AVL tree are...\n\n";
list.display();
list.loadnode(12);//12 is the id i used for one of my records.
//Calling to write back the data into the file.
list.update();
file.close();
getch();
return 0;
}
//End of program
If file.good() returned false, some previous operation on the file failed (maybe even a read operation) and raised one of the error flags of the file object. An ugly way to solve it is to use file.clear() which will clear the error flag and allow next actions to execute successfully. A better way to solve it will be to check after each operation if there's an error (file.good() is false) and understand why this operation fails and fix it.
call seekp() to move the write pointer to the begining of the stream (fstream). seekg() moves the get pointer - not going to help when writing...