I was trying to build my own binary search tree. However , my tree is not getting built. Please see code below and help.
#include<iostream>
#include<string>
using namespace std;
class Binarytree
{
private:
struct node
{
int data;
node *left;
node *right;
};
node *root;
public:
Binarytree();
void insertdata(node*,int);
void deletedata();
void printdata(node*);
void userprint(char);
void getdata(int);
};
Binarytree::Binarytree()
{
root=NULL;
cout<<"Setting root as NULL"<<endl;
}
void Binarytree::insertdata(node* temp3,int temp)
{ cout << "in insert data"<<endl;
node Dummy=node();
Dummy.data=temp;
Dummy.left=NULL;
Dummy.right=NULL;
cout << "Data To be inserted is "<<temp <<endl;
if (temp3 == NULL)
{ cout<<"Found NULL ROOT"<<endl;
temp3=&Dummy;
cout << "Entered a Data in tree"<<endl;
cout<<"Data in root"<<root->data<<endl;
}
else if (temp3->data > temp)
{ cout<<"Making a Left Recursive Call"<<endl;
insertdata(temp3->left,temp);
}
else
{ cout<<"Making a right Recursive Call"<<endl;
insertdata(temp3->right,temp);
}
}
void Binarytree::getdata(int check)
{ cout <<"in getdata"<<endl;
cout << "before insertdata"<<endl;
insertdata(root,check);
}
void Binarytree::printdata(node* printrt)
{
if (printrt ==NULL)
cout << "Nothing to print";
else
{ cout << printrt->data << endl;
printdata(printrt->left);
printdata(printrt->right);
}
}
void Binarytree::userprint(char in)
{ node* data;
data=root;
if (in == 'Y' || in == 'y')
printdata(data);
}
void main()
{ Binarytree element=Binarytree();
int userdata,i=0;
bool check = true;
while(check)
{ cout <<"Please Enter your Data"<<endl;
cin >> userdata;
element.getdata(userdata);
cout<<"FUnction returned to main"<<endl;
i++;
if(i==5)
check=false;
}
element.userprint('Y');
}
The very first value is not getting inserted in root pointer. I know there are lots of code available for doing this but if i don't code it my own I feel my learning will be limited.
So please help in figuring error in this code.
Having really tried to compile and there might be other problems... but
change
void Binarytree::insertdata(node* temp3,int temp)
to
void Binarytree::insertdata(node* &temp3,int temp)
so that the node created inside insertdata really modifies the outside pointer.
and change
node Dummy=node();
Dummy.data=temp;
Dummy.left=NULL;
Dummy.right=NULL;
to
node *Dummy=new node();
Dummy->data=temp;
Dummy->left=NULL;
Dummy->right=NULL;
As I said there might be other problems... you should worry about deleting nodes and all that...
Alternative you could create nodes outside of insertdata() and keep the same signature.
Anyway, good luck
The root cause (if you'll pardon the pun) is the way you're adding things to the root of the tree. Your code creates a temporary variable called Dummy on the stack and then takes its address. That's the first mistake because that temporary variable gets destroyed when the function ends.
The second problem is that in order to change the value of a pointer that you pass to a function, you have to pass a pointer to a pointer. In other words, your member function that was insertdata(node *, int) must become insertdata(node **, int)if you want to actually change the passed pointer rather than just a local copy as your original code had done.
To illustrate that fact, try this code.
#include <iostream>
int Y = 99;
void makeitsix(int n) {
n = 6;
}
void pointToY(int *ptr) {
ptr = &Y;
}
int main()
{
int x = 5;
int *p = &x;
std::cout << "x = " << x << ", *p = " << *p << std::endl;
makeitsix(x);
pointToY(p);
std::cout << "x = " << x << ", *p = " << *p << std::endl;
return 0;
}
When makeitsix() gets called, it's only the local copy of n that is altered, and not the value of 5 that was originally passed in. Similarly, ptr in the pointToY() function is only altering a local copy of ptr and not p that was used to call the function from within main(). If it were not so, an invocation such as makeitsix(3) would lead to some very strange effects!
I took the liberty of changing things somewhat in your code to make it a little cleaner, including
giving the node structure its own constructor
creating an extractor for the Binarytree
removing the various diagnostic printout statements (for brevity)
making the tree printout look more like a tree with the root to the left and the branches extending rightward
made some member functions private
and a few other minor things. The complete working code is below:
#include<iostream>
#include<string>
class Binarytree
{
private:
struct node
{
node(int d=0) : data(d), left(NULL), right(NULL) {};
int data;
node *left;
node *right;
};
node *root;
void insertdata(node**,int);
std::ostream& printdata(std::ostream &out, node*, int depth=0);
public:
Binarytree() : root(NULL) {};
std::ostream &printTo(std::ostream &out);
void insert(int);
};
void Binarytree::insertdata(node** temp3,int temp)
{
node *Dummy=new node(temp);
if (*temp3 == NULL) {
*temp3=Dummy;
} else if ((*temp3)->data > temp) {
insertdata(&((*temp3)->left),temp);
} else {
insertdata(&((*temp3)->right),temp);
}
}
void Binarytree::insert(int check)
{
insertdata(&root,check);
}
std::ostream &Binarytree::printdata(std::ostream &out, node* printrt, int depth)
{
if (printrt != NULL)
{
printdata(out, printrt->left, depth+1);
for (int i = 0; i < depth; ++i)
out << '\t';
out << printrt->data << std::endl;
printdata(out, printrt->right, depth+1);
}
return out;
}
std::ostream &Binarytree::printTo(std::ostream &out)
{
return printdata(out, root);
}
std::ostream &operator<<(std::ostream &out, Binarytree &b)
{
return b.printTo(out);
}
int main()
{
Binarytree element;
int userdata,i=0;
bool check = true;
while(check)
{
std::cout << "Please Enter your Data" << std::endl;
std::cin >> userdata;
element.insert(userdata);
i++;
if(i==5)
check=false;
}
std::cout << "Tree:\n" << element << std::endl;
return 0;
}
Related
I'm programming a family tree, and I was instructed to use lambda in the depth first search. I've tried to implement it, and I understand the basics of lambdas. I can't for the life of me understand how to make it work with the instructions I was getting from the teacher. Here is how I've tried to apply the code.
void depthFirst(const std::function<void(Node* )>& node) {
auto traverse = [](Node* node) {
node(this);
for( auto search: Person) {
search->depthFirst(node);
}
};
}
template<typename T>
class Node {
public:
explicit Node(const T& data, Node* parent = nullptr) : data_(data), parent_(parent) {}
explicit Node(T data): data_(std::move(data)) {}
virtual ~Node() = default;
T getData() const {
return data_;
}
void setData(T data) {
data_ = data;
}
Node *getParent() const {
return parent_;
}
void setParent(Node *parent) {
parent_ = parent;
}
bool leftExists() {
return this->left_ != nullptr;
}
void setLeft(const std::unique_ptr<Node> &left) {
left_ = left;
}
const std::unique_ptr<Node> &getLeft() const {
return left_;
}
bool rightExists() {
return this->right_ != nullptr;
}
const std::unique_ptr<Node> &getRight() const {
return right_;
}
void setRight(const std::unique_ptr<Node> &right) {
right_ = right;
}
private:
T data_; // node's data value with use of template
Node *parent_; // pointer to point at the parent node
std::unique_ptr<Node> left_;
std::unique_ptr<Node> right_;
};
template<typename T>
class Person {
public:
Person();
Person(std::string firstName, std::string lastName, int age, std::string gender, bool alive);
// setters
void setFirstName(const std::string &firstName);
void setLastName(const std::string &lastName);
void setGender(const std::string &gender);
bool isAlive() const;
void setAlive(bool alive);
void setAge(int age);
void setPerson();
// getters
const std::string& getFirstName() const;
const std::string& getLastName() const;
const std::string& getGender() const;
int getAge() const;
bool getAlive() const;
//operators
void displayPerson()const; // for testing atm
void setPerson(const Person& Person);
private:
std::string firstName_;
std::string lastName_;
int age_{};
std::string gender_;
bool alive_ = true;
};
// Functions that sets the data for the Person --->
template<typename T>
void Person<T>::setFirstName(const std::string &firstName) {
firstName_ = firstName;
}
template<typename T>
void Person<T>::setLastName(const std::string &lastName) {
lastName_ = lastName;
}
template<typename T>
void Person<T>::setGender(const std::string &gender) {
gender_ = gender;
}
template<typename T>
bool Person<T>::isAlive() const {
return alive_;
}
template<typename T>
void Person<T>::setAge(int age) {
age_ = age;
}
template<typename T>
void Person<T>::setAlive(bool alive) {
alive_ = alive;
}
// This is the default constructor, overload constructor and destructor for the person class --->
template<typename T>
Person<T>::Person(std::string firstName, std::string lastName, int age, std::string gender, bool alive) :
firstName_(std::move(firstName)), lastName_(std::move(lastName)), age_(age), gender_(std::move(gender)), alive_(alive) {}
template<typename T>
Person<T>::Person() {
}
// Functions that gets the data for the Person --->
template<typename T>
int Person<T>::getAge() const {
return 0;
}
template<typename T>
const std::string &Person<T>::getFirstName() const {
return this->firstName_;
}
template<typename T>
const std::string &Person<T>::getLastName() const
{
return this->lastName_;
}
template<typename T>
const std::string &Person<T>::getGender() const
{
return this->gender_;
}
template<typename T>
bool Person<T>::getAlive() const {
return false;
}
template<typename T>
class FamilyTree
{
public:
FamilyTree();
explicit FamilyTree(Node<T>* root); // Create new tree
FamilyTree(T data):
/*
void addNewPerson();
void addFather();
void addMother();
*/
void addNode(T data);
bool isEmpty();
private:
Node<T> *root_;
void addNode(Node<T>* root, T data);
};
template<typename T>
FamilyTree<T>::FamilyTree(Node<T> *root) {
this->root_ = root;
}
template<typename T>
bool FamilyTree<T>::isEmpty() {
return this->root_ == nullptr;
}
template<typename T>
FamilyTree<T>::FamilyTree() {
this->root_ = nullptr;
}
template<typename T>
void FamilyTree<T>::addNode(T data) {
if(root_ == nullptr)
root_ = std::make_unique(Node<T>(data));
else
addNode(root_, data);
}
//main
//just for test
void Person::displayPerson() const {
std::cout << "First Name: " << this->getFirstName() << std::endl;
std::cout << "Last Name: " << this->getLastName() << std::endl;
std::cout << "Age: " << this->getAge() << std::endl;
std::cout << "Gender: " << this->getGender() << std::endl;
std::cout << "Alive: " << this->getAlive() << std::endl << std::endl;
}
//main
int main(){
// Node test
Node node;
Node* setLeft(reinterpret_cast<Node *>(1));
Node* setRight(reinterpret_cast<Node *>(2));
std::cout << node.getData() << std::endl;
std::cout << node.getLeft() << std::endl;
std::cout << node.getRight() << std::endl;
//Person test
Person p0, p1("Robert", "Dane", 37, "Male", 1), p2("John", "Doe", 35, "Female", 1);
p0.displayPerson();
p1.displayPerson();
p2.displayPerson();
// FT test
return 0;
}
void ignoreLine() // inspiration from here: https://stackoverflow.com/questions/11523569/how-can-i-avoid-char-input-for-an-int-variable
{
std::cin.clear();
std::cin.ignore(INT_MAX, '\n');
}
void showMainMenu() // hold the output for the main menu
{
std::cout << "Welcome" << std::endl;
std::cout << "Please enter a number for your choice below:\n" << std::endl;
std::cout << "(1) Add new person to tree" << std::endl;
std::cout << "(2) Show information for a person" << std::endl;
std::cout << "(3) Print complete family-tree" << std::endl;
std::cout << "(4) Used for testing new choices" << std::endl;
std::cout << "(0) Quit" << std::endl;
std::cout << "\nYour choice: " << std::endl;
}
int main()
{
familyTree fT; // used to access/init. familytree class.
bool exit = true;
int option;
while (exit)
{
showMainMenu();
std::cin >> option;
while (std::cin.fail())
{
ignoreLine();
std::cout << "\nOnly a number between 0 and 10 is allowed: ";
std::cin >> option;
}
switch (option)
{
case 1:
fT.addNewPerson();
break;
case 2:
std::cout << "Enter name of person to show information: ";
int temp;
std::cin >> temp;
fT.show(fT.search(temp));
break;
case 3:
fT.printInOrder(fT.root, 0);
break;
case 4:
/* n/a */
break;
case 0:
exit = false;
break;
default: ;
}
std::cout << "\nPress enter to continue.." << std::endl;
ignoreLine();
}
return 0;
Old code that worked:
person *familyTree::traverseLeft(person *ptr, const std::string& person)
{
ptr = ptr->left;
while (ptr != nullptr)
{
if ((ptr->firstName) == person) {
return ptr;
}
else if (traverseRight(ptr, person) != nullptr)
{
return traverseRight(ptr, person);
}
else
{
ptr = ptr->left;
}
}
return nullptr;
}
person *familyTree::traverseRight(person *ptr, const std::string& person)
{
ptr = ptr->right;
while (ptr != nullptr)
{
if ((ptr->firstName) == person)
{
return ptr;
}
else if (traverseLeft(ptr, person) != nullptr)
{
return traverseLeft(ptr, person);
}
else
ptr = ptr->right;
}
return nullptr;
edit: The teacher told me that node(this); was supposed to point to the current node being searched. I may not have the most pedagogical correct teacher. But it is supposed to search the binary tree depth first, node for node. There is no use of vector or indexes, as I was told it was not needed. There is a class node and a class person that is implemented in to the node. If there is a better way of traversing a tree than this, feel free to let me know.
edited to add Person and Node.
edited to show old code that we got told to burn. I only got the instructions on lambda in person, but in short, was told to create lambda to use on a current node within a void function search, then go right, then go left. It could be reused in delete and other functions.
edited to add last of all code. Should I just go back to the old code (but less OOP) that I know compile and works? I got so much bad reviews on the old one that my group decided to start a new. But right now it's just a mess. (Keep in mind that the "new" code now is on different header files, so it might be more messy in regards to the console and main)
Is there a reason why you direct initialize your private variables in class Person as rvalues (ie. std::move?) ? std::string can bind permitted rvalues as long as they're const.
For instance the code below:
template<typename T>
Person<T>::Person(std::string firstName, std::string lastName, int age, std::string gender, bool alive) \
: firstName_(std::move(firstName)), lastName_(std::move(lastName)), age_(age), gender_(std::move(gender)), alive_(alive) {}
Could be:
template <typename T>
Person<T>::Person(std::string firstName, std::string lastName, int age, std::string gender, bool alive) \
: firstName_{firstName}, lastName_{lastName}, age_{age}, gender_{gender}, alive_{alive} {}
Making the the members in Person rvalues would be preparing them for a move, which it does not look like you're doing earlier in the code.
template <typename T>
void Person<T>::setFirstName(const std::string &firstName)
{
firstName_ = firstName;
}
The values are being passed as lvalue references in the function parameters of Person, which you are changing to rvalues in the constructor of said class. There is no need to do this. They are not meant to be temporary values. The use of {} instead of () eliminates the chance of implicit conversion (narrowing) on part of the members.
You're thinking inside out or upside down - you should pass a lambda (or another function) to this function, and this should apply that function in a depth-first manner.
You also need a helper function that takes a Node* that indicates the current node.
A very simple example, with a preorder traversal:
private:
void traverse(const std::function<void(Node*)>& action, Node* current)
{
if (current != nullptr)
{
action(current);
traverse(action, current->getLeft());
traverse(action, current->getRight());
}
}
public:
void traverse(const std::function<void(Node*)>& action)
{
traverse(action, root_);
}
And you are supposed to use it something like this:
FamilyTree tree = ... whatever ...;
auto process = [](const Node* p) { ... print p ... };
// This will now print in preorder.
tree.traverse(process);
I am trying to create a program that takes N random nodes from user input and creates a random integer that is put into a binary tree and then copied into a priority queue. The integer becomes the key for each node and another integer counts the frequency of the key. I run into issues when I copy into the priority queue because I get duplicates and I need to remove them. I tried to create a set through the node constructor but I get the error above in the .cpp file.
#include <iostream>
#include <random>
#include <ctime>
#include <queue>
#include <set>
#include <functional>
#include <algorithm>
#include<list>
#include "Q7.h"
using namespace std;
int main()
{
node * root=NULL;
node z;
int n,v;
vector<int> first;
vector<int>::iterator fi;
default_random_engine gen(time(NULL));
cout<<"how many values? "; cin>>n;
for(int i=0; i<n; i++)
{ (v=gen()%n);
first.push_back(v);
if(root==NULL){root = node(set(v));}///This is where I get the error!!
else{
root->addnode(v);
}
}
z.unsortedRemoveDuplicates(first);
cout<<"Binary Tree in a depth first manner with Duplicates removed!"<<endl;
for ( fi = first.begin() ; fi != first.end(); ++fi{cout<<"Node "<<*fi<<endl;}
cout<<"-------------------"<<endl;
root->display();
cout<<"-------------------"<<endl;
cout<<"-------------------"<<endl;
root->display_Queue1();
cout<<"-------------------"<<endl;
return 0;
}
my .h file
class node
{
public:
node(){left=NULL; right=NULL; ct = 1;}
node set(int v) {val = v; left=NULL; right=NULL; ct=1;}
node (int Pri, int cat)
: val(Pri), ct(cat) {}
friend bool operator<(//sorts queue by lowest Priority
const node& x, const node& y) {
return x.val < y.val;
}
friend bool operator>(//sorts queue by greatest Priority
const node& x, const node& y) {
return x.ct > y.ct;
}
friend ostream&//prints out queue later
operator<<(ostream& os, const node& Pri) {
return os <<"my value = "<<Pri.val<<" occured "<<Pri.ct<<" times";
}
int unsortedRemoveDuplicates(vector<int>& numbers)
{
node set<int> seenNums; //log(n) existence check
auto itr = begin(numbers);
while(itr != end(numbers))
{
if(seenNums.find(*itr) != end(seenNums)) //seen? erase it
itr = numbers.erase(itr); //itr now points to next element
else
{
seenNums.insert(*itr);
itr++;
}
}
return seenNums.size();
}
priority_queue<node, vector<node>, greater<node> > pq;
priority_queue<node, vector<node>, less<node> > pq1;
void addnode(int v)
{
if(v==val){ct++;}
pq.emplace(node (set (v)));///No error here for set with constructor why??
pq.emplace(node (set (v)));
if(v<val)
{
if(left==NULL){left=new node(set(v));
}
else{left->addnode(v);
}
}
else
{
if(right==NULL){right = new node (set(v));
}
else{right->addnode(v);
}
}
}
int display()
{
if(left!=NULL){left->display();}
cout<<"frequency "<<ct<<" value"<<val<<endl;
if(right!=NULL){right->display();}
}
void display_Queue()
{
cout << "0. size: " << pq.size() << '\n';
cout << "Popping out elements from Pqueue..."<<'\n';
while (!pq.empty())
{
cout << pq.top() << endl;
pq.pop();
}
cout << '\n';
}
void display_Queue1()
{
cout << "0. size: " << pq1.size() << '\n';
cout << "Popping out elements from Pqueue..."<<'\n';
while (!pq1.empty())
{
cout << pq1.top() << endl;
pq1.pop();
}
cout << '\n';
}
private:
int val; ///value in that node
int ct;
///ct = count of that value
node * left;
node * right;
};
Congratulations, with this line:
root = node(set(v));
You have discovered why people here often say to avoid using using namespace std;. This is being interpreted as:
root = static_cast<node>(std::set(v));
Instead of what you want, which might be:
root = new node();
root->set(v);
First, note that we need to use new as we are creating a new node, not trying to cast a node to a node, which would have also given another compiler error about trying to assign a value to a pointer.
Next, note that you don't get the error in the header file as there is no using namespace std; there, and since it is in a member function, the line:
void node::addnode(int v)
{
//...
pq.emplace(node (set (v)));///No error here for set with constructor why??
//...
}
Is interpreted as:
pq.emplace(static_cast<node>(this->set(v)));
However, is this what you really want to do?
Furthermore, I would change the constructors to be:
public:
node (int Pri = 0, int cat = 1)
: val(Pri), ct(cat), left(NULL), right(NULL) {}
// DELETED node (int Pri, int cat)
Thus you can do:
root = new node(v);
And it will work as I think you expect it to.
this is my first time asking a question. The forums have been super helpful to me so I will try and only give you the juicy parts:
I have two functions, one is a Search function that searches a precreated binary search tree through pointers (I can display the search tree through a different function, so I know it's populated) for a specific value. It puts the info from that node into a predefined data structure Nubline with the same types of varaibles (int, float, and string), and then returns that data structure.
Here's my code:
struct node
{
int id;
string name;
float balance;
node *left;
node *right;
};
node *rootID, *rootName;
struct Nubline
{
int ID;
string Name;
float Amnt;
};
//Search function; the node is a pointer to a linked list with move id's node *left and node *right;
Nubline SearchbyID(node* &t, int x)
{
if (t != NULL)
{
if (t->id == x)
{
Nubline r;
r.ID = t->id;
r.Name = t->name;
r.Amnt = t->balance;
return r;
}
SearchbyID(t->left, x);
SearchbyID(t->right, x);
}
}
//function that calls the search function
void BalancebyID()
{
int num;
cout << "\tWhat is your ID number? "; cin >> num;
Nubline duke = SearchbyID(rootID, num);
cout << "\t\t"<< duke.Name << " your balance is $" << duke.Amnt;
}
void main()
{
//calling statement
BalancebyID();
system("pause");//pausing to view result
}
It throws the following error:
Expression: "(_Ptr_user & (_BIG_ALLOCATION_ALIGNMENT -1)) == 0
I think I've narrowed down the issue to the function initialization, because I can make the function void and it runs (without all the other code, of course). I can also void the function, set an arbitrary global variable of type Nubline and put it where the variable "r" is, and then use it in my BalancebyID function, but it just displays zero, so I can assume it's not populating.
Sorry for the long-winded post.
Tl;dr: how do I create a function that returns a data structure?
To ensure SearchbyID work properly, you should add return to all conditions.
Also, you could make the returning type Nubline* then you can return a nullptr to indicate nothing found.
Nubline* SearchbyID(node* t, int x)
{
if(t == nullptr) return nullptr;
//else
if (t->id == x)
{
auto r = new Nubline();
r->ID = t->id;
r->Name = t->name;
r->Amnt = t->balance;
return r;
}
auto pLeft = SearchbyID(t->left, x);
if (pLeft) return pLeft;
return SearchbyID(t->right, x);
//return NULL if nothing found
}
Alright here's my solution:
I voided the function, used a global variable Nubline r; and set t to that as follows:
void SearchbyID(node* &t, int x)
{
if (t != NULL);
{
if (t->id == x)
{
r.ID = t->id;
r.Name = t->name;
r.Amnt = t->balance;
}
//I also changed this to make it more efficient and not throw an access violation up by the if(t->id == x) statement
if (x < t->id)
{
SearchbyID(t->left, x);
}
if (x > t->id)
{
SearchbyID(t->right, x);
}
}
}
//PART B
//Option 1: show Balance when ID is given
void BalancebyID()
{
int num;
cout << "\tWhat is your ID number? "; cin >> num;
SearchbyID(rootID, num);
cout << "\t\t"<< r.Name << " your balance is $" << r.Amnt;
}
This is what worked for me. Thank you all for your solutions; it helped me isolate the problem and find a solution.
I was wondering how I could call the toString() method in my Link List of the class BoxClass. BoxClass has a double length, width and height.
my BoxClass:
class BoxClass{
private:
double length;
double width;
double height;
public:
// Default constructor w/ no parameters
BoxClass(){
length = 0;
width = 0;
height = 0;
}
// Constructor with arguments
BoxClass(double boxLength, double boxWidth, double boxHeight){
length = boxLength;
width = boxWidth;
height = boxHeight;
}
// Setters and Getters
void setLength(double boxLength){
length = boxLength;
}
double getLength(){
return length;
}
void setWidth(double boxWidth){
width = boxWidth;
}
double getWidth(){
return width;
}
void setHeight(double boxHeight){
height = boxHeight;
}
double getHeight(){
return height;
}
// Returns the volume of the boxes
double Volume(){
return (length * width * height);
}
// toString method for boxes, returns "(length) x (width) x (height) string
string toString(){
return ("(" + to_string(length)+ "x" + to_string(width) + "x" + to_string(height) + ")");
}
}; // End of BoxClass() class
LinkNode.h
//Template ListNode class definition.
#ifndef LINKNODE_H
#define LINKNODE_H
template <typename T> class LinkList;
template <typename T> class LinkNode{
friend class LinkNode <T>;
public:
LinkNode(const T &);
T getData()const;
T data;
LinkNode <T> *nextPtr;
};
template <typename T> LinkNode <T>::LinkNode(const T &info):data(info), nextPtr(NULL){
// Empty body
}
template <typename T>T LinkNode<T>::getData()const{
return data;
}
#endif
Main (Creating the class, adding it to Link List
// Create the Box class
BoxClass userBox(length, width, height);
// Add box class to Link List
Box.insertNode(userBox);
Box.print();
LinkList.h print() method
template<typename T>void LinkList<T>::print()const {
// To list off nodes
int counter = 1;
if (isEmpty()) {
cout << "No boxes in list!\n";
} else {
LinkNode<T>*currentPtr = firstPtr;
cout << "Your boxes in increasing order of volume is:\n";
// while (currentPtr) {
while (currentPtr != NULL) {
// Output as "#. (length x width x height)
cout << counter << ". " << currentPtr->data << endl;
printf(" %i. %.2f\n", counter, currentPtr->data);
currentPtr = currentPtr->nextPtr;
counter++;
}
}
}
LinkList.h
//Template LinkList class definition.
#ifndef LINKLIST_H
#define LINKLIST_H
#include <iostream>
#include "LinkNode.h"
using namespace std;
template<typename T> class LinkList {
public:
LinkList();
void addNode(const T &);
void insertNode(const T &);
bool isEmpty() const;
void print() const;
private:
LinkNode<T>*firstPtr;
LinkNode<T>*getNewNode(const T &);
};
template<typename T>LinkList<T>::LinkList() :firstPtr(NULL) {
// Empty body
}
template <typename T>void LinkList<T>::insertNode(const T &value) {
LinkNode<T>*newPtr = getNewNode(value);
bool inserted = false;
if (isEmpty() || (newPtr->data < firstPtr->data)) {
newPtr->nextPtr = firstPtr;
firstPtr = newPtr;
// cout << " " << newPtr->data << " inserted at front of list.\n";
printf(" %.2f inserted at front of list.\n", newPtr->data);
} else {
LinkNode<T>*currentPtr = firstPtr;
while (currentPtr->nextPtr && !inserted) {
if (newPtr->data < currentPtr->nextPtr->data) {
// cout << " " << newPtr->data << " inserted before " << currentPtr->nextPtr->data << ". " << endl;
printf(" %.2f inserted before %.2f.\n", newPtr->data, currentPtr->nextPtr->data);
newPtr->nextPtr = currentPtr->nextPtr;
currentPtr->nextPtr = newPtr;
inserted = true;
} else {
currentPtr = currentPtr->nextPtr;
}
}
if (!inserted) {
currentPtr->nextPtr = newPtr;
printf(" %.2f inserted at the end of list.\n", newPtr->data);
}
}
}
template<typename T>bool LinkList<T>::isEmpty()const {
return firstPtr == NULL;
}
template<typename T>LinkNode<T>*LinkList<T>::getNewNode(const T &value) {
return new LinkNode<T>(value);
}
template<typename T>void LinkList<T>::print()const {
// To list off nodes
int counter = 1;
if (isEmpty()) {
cout << "No boxes in list!\n";
} else {
LinkNode<T>*currentPtr = firstPtr;
cout << "Your boxes in increasing order of volume is:\n";
// while (currentPtr) {
while (currentPtr != NULL) {
// Output as "#. (length x width x height)
cout << counter << ". " << currentPtr->data << endl;
printf(" %i. %.2f\n", counter, currentPtr->data);
currentPtr = currentPtr->nextPtr;
counter++;
}
}
}
#endif
So again, my question is- How do I go about traversing the list and calling the toString() BoxClass method? I tried everything from cout << data.toString() << endl; but that doesn't work. I've been stuck on this for days, can someone help me out?
edit: added LinkList.h
When you write template <typename T> class LinkNode{ you are specifically stating that your node class will have no built-in knowledge of the type of the node that it contains.
You have not shown us your LinkList<T> class, but obviously, the same thing applies to it: since it consists of LinkNode<T> it has to also accept a generic parameter of type <T>, so it cannot have built-in knowledge of the actual type of <T> either.
Therefore, you cannot suddenly introduce a method which has such knowledge. It does not make sense. "It does not compute".
What you need to do instead is add this print() method of yours elsewhere, and make it accept a LinkList<BoxClass>. Then, it will be able to view the LinkNodes as LinkNode<BoxClass>, and it will be able to invoke linkNode.data.toString().
The problem is that your implementation of LinkList<T> class has no way for the client code to go through each node of the list in a loop. What if we don't want to print, but do something else with each box?
In addition, it would look weird if I have a LinkList<Widget>, and I see the text when I call print():
"Your boxes in increasing order of volume is:";
I would say, "what boxes? what volume? I have Widgets, not boxes".
A more complete implementation would look something like this (caveat: This has not been compiled. It is to give you the gist of what you should be doing):
template<typename T> class LinkList {
public:
LinkList();
void addNode(const T &);
void insertNode(const T &);
bool isEmpty() const;
// this is what you're missing from the current implementation
typedef LinkNode<T>* Iterator;
Iterator begin() { return firstPtr; }
Iterator next(Iterator ptr) { return ptr->nextPtr; }
Iterator end() { return NULL; }
private:
LinkNode<T>* firstPtr;
LinkNode<T>* getNewNode(const T &);
};
Then with this, the print function need not be part of the linked list. It can live on the outside:
LinkList<BoxClass> boxList;
//...
void print()
{
if (boxList.isEmpty())
cout << "No boxes in list!\n";
else
{
int counter = 1;
cout << "Your boxes in increasing order of volume is:\n";
// get first box
LinkList<BoxClass>::Iterator curBox = boxList.begin();
// loop until no more boxes
while (curBox != boxList.end())
{
// now use curBox to do whatever you want with this box
BoxClass& b = curBox->getData();
cout << counter << ". " << b.toString();
// go to the next box
curBox = boxList.next(curBox);
counter++;
}
}
}
Note how print is no longer a member of LinkList. Also, note the typedef to give us a "nice" name for the LinkNode pointer that the client uses. The comments should be self-explanatory.
I didn't want to overcomplicate the code by introducing a "real" iterator (i.e. overloaded ++), but that operator would replace the LinkList<T>:::next() function call. I leave that to you as an additional exercise.
The following code is printing out 343. I don't understand why it isn't taking in currentDirectory by reference and updating what it's pointing to to a subdirectory of the root instance.
I would expect it to output 344.
#include <iostream>
using namespace std;
class Directory;
struct Node{
Node* prev;
Node* next;
Directory* data;
};
class Directory{
public:
int testValue;
Node* subDirectories;
void addSubdirectory(int testValue){
Directory* newDirectory = new Directory(testValue);
Node* elem = new Node;
elem->prev = NULL;
elem->data = newDirectory;
elem->next = NULL;
subDirectories = elem;
}
Directory(int x){
testValue = x;
}
};
void testFunction(Directory* x){
x = x->subDirectories->data;
cout << x->testValue;
}
int main(){
Directory* root = new Directory(3);
root->addSubdirectory(4);
Directory* currentDirectory = root;
cout << currentDirectory->testValue;
testFunction(currentDirectory);
cout << currentDirectory->testValue;
}
I've tried a simplified example that works fine:
#include <iostream>
using namespace std;
class Directory;
class Directory{
public:
int testValue;
Directory(int x){
testValue = x;
}
};
void testFunction(Directory* x){
x->testValue = 4;
cout << x->testValue;
}
int main(){
Directory* root = new Directory(3);
Directory* currentDirectory = root;
cout << currentDirectory->testValue;
testFunction(currentDirectory);
cout << currentDirectory->testValue;
}
This prints out 344 as expected. This one is passing it in by reference.
Your problem is that you are passing by value not by reference. The instance that is being passed to "testfunction()" is "currentDirectory" which is a pointer to object. So if you intend to pass by reference it should be like this:
void testFunction(Directory* &x){
x = x->subDirectories->data;
cout << x->testValue;
}
You are making a copy of type Directory* and passing it into testFunction as an argument. That copy, x, is not a reference to the pointer root.
This is probably what you want:
void testFunction(Directory* &x){
x = x->subDirectories->data;
cout << x->testValue;
}
Or if you prefer the double pointer route you would have:
void testFunction(Directory** x){
(*x) = (*x)->subDirectories->data;
cout << (*x)->testValue;
}
// the call turns into
testFunction(¤tDirectory)
Your simplified example works because you are not actually assigning to the variable that is passed-by-value, x:
void testFunction(Directory* x){
x->testValue = 4; // assigning pointed-to value, not pointer
cout << x->testValue;
}
Long story short, pointer-to-type is a type in and of itself too. Passing a pointer by reference takes the same changes as any other type.
Alternately, you could create an object of the class rather than a pointer. Note, this would require you to add a copy constructor (and, hopefully, a destructor, and overloaded operator=).
Directory root(3);
root.addSubdirectory(4);
//Assuming you overload operator=
Directory currentDirectory = root;
cout << currentDirectory.testValue;
testFunction(currentDirectory);
Where
void testFunction(Directory & x);