Well I have a task to make BST (Binary Search Tree) on a template. And I'm stuck on conversion problem, couse using template :/. I don't know how to get over it. I tried this code without template and it works normally.
#include <iostream>
using namespace std;
template <class T> struct drzewo{
private:
int value;
drzewo *l ,*r;
public:
T NewDrzewo(int key){
struct drzewo *temp=(struct drzewo*)malloc(sizeof(struct drzewo));
temp->value=key;
temp->l=temp->r=NULL;
return temp;
}
void inorder(struct drzewo *root) {
if (root != NULL) {
inorder(root->l);
cout << root->value << " -> ";
inorder(root->r);
}
}
T insert(struct drzewo *drzewo, int value) {
if (drzewo == NULL) return NewDrzewo(value);
if (value < drzewo->value){
drzewo->l=insert(drzewo->l, value);
}
else{
drzewo->r=insert(drzewo->r, value);
}
return drzewo;
}
};
int main(int argc, char** argv) {
struct drzewo <int> *root = NULL;
root->insert(root, 8);
return 0;
} ```
You are using the template machinery incorrectly.
template <class T> struct drzewo{
private:
int value; // THIS MAKES NO SENSE
The idea of the template is to pass thet type of the stored element as a parameter and not to hard code it. Thus you should be using
T value;
instead of
int value;
Since T is the type of your stored element and not the type of your tree,
T NewDrzewo(int key){
is also wrong, you should be using
drzewo* NewDrzewo(T key){
Likewise, T insert(... int value) should be drzewo* insert(... T value).
There are other issues unrelated to this one, for example (in no particular order):
Using malloc. Don't do that, use new instead.
Not using constructors and destructors.
Using elaborate-type-specifiers (struct drzewo) without any reason. Use drzewo instead.
Using the obsolete NULL macro. Use nullptr instead.
using namespace std is dangerous, never do that.
insert and NewDrzewo should be static functions as they do not use this. root->insert(root, 8) should be root = drzewo<int>::insert(root, 0) because root-> is illegal when root is a null pointer.
Related
In tree, while taking input (inside takeInput function), tree node was made using dynamic allocation, but I tried doing it statically, but as tree node were declared inside a function locally it should have not worked because its a local variable (I was expecting a error). But Why am I able print it even after that:
NOTE: this code takes input recursively (and may not be the best way)
#include<bits/stdc++.h>
using namespace std;
template <typename T>
class treeNode{
public:
T data;
vector <treeNode<T>> children;
treeNode(T data){
this->data=data;
}
};
treeNode<int> takeInput(){
int rootdata;
cout<<"Enter Node"<<endl;
cin>>rootdata;
// treeNode<int>* root= new treeNode<int>(rootdata);
treeNode<int> root(rootdata); //Static Allocation
cout<< "Enter Number of children of "<<rootdata<<endl;
int n;
cin>>n;
for(int i=0;i<n;i++){
treeNode<int> child = takeInput();
root.children.push_back(child);
}
return root;
}
void printTree(treeNode<int> root){
cout<<root.data<<": ";
for(int i=0;i<root.children.size();i++){
cout<<root.children[i].data<<",";
}
cout<<endl;
for(int i=0; i<root.children.size();i++){
printTree(root.children[i]);
}
}
int main(){
treeNode<int> root= takeInput();
printTree(root);
return 0;
}
Following code is using dynamic allocation:
#include<bits/stdc++.h>
using namespace std;
template <typename T>
class TreeNode{
public:
T data;
vector <TreeNode<T>*> children;
TreeNode(T data){
this->data=data;
}
};
TreeNode<int>* takeInput(){
int rootdata;
cout<<"Enter node"<<endl;
cin>>rootdata;
TreeNode<int>* root=new TreeNode<int>(rootdata);
cout<<"Enter number of children of "<<rootdata<<endl;
int n;
cin>>n;
for(int i=0;i<n;i++){
TreeNode<int>* child=takeInput();
root->children.push_back(child);
}
return root;
}
void printTree(TreeNode<int>* root){
if (root == NULL){
return;
}
cout<< root->data<<" :";
for(int i=0;i<root->children.size(); i++){
cout<<root->children[i]->data<<",";
}
cout<<endl;
for(int i=0;i<(*root).children.size();i++){
printTree(root->children[i]);
}
}
int main(){
TreeNode<int>* root = takeInput();
printTree(root);
return 0;
}
Your code is equivalent to
A foo() {
A a;
a = bar();
return a;
}
a is just copied into the return value (That copy might be avoided too). Replace A with treeNode<int> and the semantics remain the same.
Why then the dynamic code?
I'm guessing the code version using dynamic allocation was probably coded up thinking that something like
struct A {
std::vector<A> vecA;
};
is a recursive definition for A since when vecA is declared A is an incomplete type. But that's not the case anymore and this is officially into C++17 (though it worked for some compilers in earlier versions too) where some STL containers can do with incomplete type. Hence it used the form
vector <TreeNode<T>*> children;
storing pointers to the children and hence that code, which is similar to the familiar LinkedList Node data structure definition
struct Node {
int data;
Node* next; // The TreeNode stores a vector of pointers instead.
};
Conclusion
Stack allocation is usually preferred when possible since it's faster than the heap route. Also, that code with dynamic allocation brings in the headache of memory management unless smart pointers are being used. It's just not needed for your code. Go with the stack allocation route for your example and let std::vector take care of maintaining the dynamic array.
I'm trying to insert a Packet object into this binary search tree. But the problem is, I don't really know of a good-enough way of doing this or how to go about doing it. I'm looking for some pointers in the right direction and to be shown what to do to tackle this problem.
Please:
Ignore my usage of namespace std; because this is for educational
purposes and I'm not rly (as of now) looking to go further than that!
Help me with my specific question and if possible, show me how I
could fix this problem.
<< Take a look at my code >>
Main.cpp:
#include <iostream>
#include "BST.h"
#include "Packet.h"
// IGNORE the USAGE of namespace std. as this is purely a testing program for educational purposes.
// It is NOT implementation for a real program.
using namespace std;
int main() {
cout << "-------------------------------------------------------" << endl;
cout << "Testing BST" << endl;
cout << "-------------------------------------------------------" << endl;
BST test1;
Packet packetTest(123, "This is a packet of cheese.", 12.95, 10);
// test1.insert(How should I choose to insert Packet? That's the question.);
system("pause");
}
BST.h:
#pragma once
#include "Packet.h"
using namespace std;
class BST {
struct Node {
Node() : rlink(nullptr), llink(nullptr) {};
~Node() {};
// Store packet here (for instance Packet *data or something)...
Node *rlink, *llink;
};
public:
BST();
// void insert(How should I choose to insert Packet? That's the question.);
void insert(Node *&p, Node *newNode);
void preorderTraversal() const;
void destroyTree();
~BST();
private:
Node * root;
void destroyTree(Node *&p);
void preorderTraversal(const Node *p) const;
};
BST.cpp (need guidance here, see below code to see what I mean):
#include "BST.h"
#include <iostream>
BST::BST() : root(nullptr) {}
// Need guidance here. What should I do for this function? How can I insert this object called Packet into the BST?
/*void BST::insert(How should I choose to insert Packet? That's the question.) {
Node *newNode = new Node;
...
insert(root, newNode);
}*/
void BST::insert(Node *&p, Node *newNode) {
if (p == nullptr) {
p = newNode;
}/*else if (p's data's getPartId() > newNode's data's getPartId()){
insert(p->llink, newNode);
}*/else {
insert(p->rlink, newNode);
}
}
void BST::preorderTraversal() const {
if (root == nullptr) {
cerr << "There is no tree.";
}
else {
preorderTraversal(root);
}
}
void BST::preorderTraversal(const Node *p) const {
if (p != nullptr) {
// cout << p->data->getPartId() << " "; Need to handle Packet's data here. But we need to implement Packet insection first!
preorderTraversal(p->llink);
preorderTraversal(p->rlink);
}
}
void BST::destroyTree(Node *&p) {
if (p != nullptr) {
destroyTree(p->llink);
destroyTree(p->rlink);
delete p;
p = nullptr;
}
}
void BST::destroyTree() {
destroyTree(root);
}
BST::~BST() {
destroyTree(root);
}
Packet.h:
#pragma once
#include <string>
using namespace std;
class Packet {
public:
Packet(int partId, string description, double price, int partCount) :
partId(partId), description(description), price(price), partCount(partCount) {}
int getPartId() const { return partId; }
private:
int partId;
string description;
double price;
int partCount;
};
This was my previous implementation of insert in BST.cpp:
void BST::insert(Packet &data) {
Node *newNode = new Node;
newNode->data = &data;
insert(root, newNode);
}
As you can see, I don't believe that this is ideal. I mean I had to use & reference twice. Is there a more elegant solution and may I get guidance in regards to that?
Q: How can I insert this object called Packet into the BST?
A: To create a relationship between the BST and Packet class, you must define one in some sort of way. Best practice calls for an association which imposes the least amount of coupling between the related classes.
I have implemented an association in your solution in the place I found most suitable ie. the rlink and llink pointers of struct Node of class BST.
// Store packet here (for instance Packet *data or something)...
Packet* rlink, * llink;
A relationship is the only way you will be able to access getPartId() from a Node or BST object. Albeit the Packet class does not manage any resources so it does not require memory management, association is just a fancy word for a loosely coupled relationship between classes, which is the case here.
Be careful when calling functions recursively, as you have in void BST::insert(Node *&p, Node *newNode). You shouldn't call a function recursively without an exit condition and never really use recursion unless you have to as iterations are a stack-memory saving alternative. I saw no need for recursion in your insert function so I took it out. I'm hoping what I replaced them with is of some use to you:
void BST::insert(Packet& p) {
Packet* newPacket = new Packet(p);
insert(root, newPacket);
}
void BST::insert(Node*& p, Packet* newPacket) {
if (p == nullptr) {
p = new Node;
p->llink = newPacket;
}else if ((p->llink->getPartId()) > newPacket->getPartId()){
p->llink = newPacket;
}else {
p->rlink = newPacket;
}
}
I then went on to say:
void BST::preorderTraversal(const Node* p) const {
if (p != nullptr) {
cout << p->llink->getPartId() << " \n";
}
}
void BST::destroyTree(Node*& p) {
if (p != nullptr) {
delete p;
p = nullptr;
}
}
As I said, a relationship is the only way you will be able to access getPartId() from a Node or BST object.
Regarding the comments, I agree. Encapsulation requires keeping all data members private and only exposing methods when you have to. My solution allows you to keep the function
private:void insert(Node*& p, Packet* newPacket);
As you have kept Node completely hidden by overloading the preorderTraversal()
Good job and hope I helped!
In the code below I attempt to create a linked list of strings. I then use the linked list to store output generated by a function (named myFunction) which calls itself recursively. When testing/debugging the code, I noticed that if I print the contents of the linked list after executing the function (which should add items to the linked list) nothing prints out. However, if I attempt to print the linked list after adding items from inside the function it works fine.
It appears that the entire linked list is deleted after the call to myFunction. On the other hand, I'm using dynamic memory allocation when I add elements to the linked list so I don't see the issue.
Please help!
#include <cstdlib>
#include <iostream>
template <class T>
class node{
public:
node *next;
T data;
node(){next=0;};
void print();
};
template <class T>
void node<T>::print(){
std::cout << data;
}
template <class T>
class List{
public:
node<T> *head;
List(){head=0;};
void add(T data);
void print();
int len();
};
template <class T>
int List<T>::len(){
int i=0;
node<T> *current=head;
while(current!= 0){
i++;
current=current->next;
}
return i;
};
template <class T>
void List<T>::add(T myData){
node<T> *current=head;
if(head==0){
head= new node<T>;
head->data=myData;
}
else{
while(current->next!=0){
current=current->next;
}
current->next = new node<T>;
current->next->data=myData;
}
}
template <class T>
void List<T>::print(void){
node<T> *current=head;
if(head==0){
return;
}
else{
do{
std::cout << current->data << " ";
current=current->next;
}while(current!=0);
}
}
void myFunction(List<std::string> myList, int n, std::string starter, int leftParens, int rightParens){
int remainingLength = leftParens+rightParens;
if(remainingLength==0){
myList.add(starter);
std::cout <<myList.len() << std::endl;
}
if(leftParens >0){
myFunction(myList, n, starter+"(", leftParens-1, rightParens);
}
if(leftParens==0 and rightParens >0){
myFunction(myList, n, starter+")", leftParens, rightParens-1);
}
}
int main(int argc, char** argv) {
List<std::string> myList;
myFunction(myList, 5, "", 5, 5);
std::cout <<myList.len();
}
You are passing myList to myFunction by value. Any changes made to myList in the function are changes to the copy, not the original myList in main.
Change myFunction so that it accepts its argument by reference. Then, any changes made to it in myFunction will also be visible in main.
void myFunction(List<std::string>& myList, int n,
// ^^
std::string starter, int leftParens, int rightParens){
You need to use reference if you want to update the variable in the caller context (in other words, if you want to change the variable in main).
Whenever a class allocates memory, you probably need to follow the "rule of three" (constructor, copy-constructor, copy-assignment operator). If you don't, you'll get into trouble if you ever make a copy of the original class [like your call to myFunction as it currently stands]
So I have 2 classes, a templated class named Node<T> and a nontemplated one named Context. I have a few methods in Context that need to return any type of Node<T>.
For instance, sometimes it will need to return a Node<double> and sometimes an Node<int> etc. I also have some methods that I’d like to have that take any type of Node<T> as a parameter.
Is there any way I can do this that doesn’t include having separate methods in Context for each possible case?
class Node
{
T Val;
public:
Node(T value) : Val(val) {}
T getVal() { return Val; }
}
class Context
{
Node<type>* divide(Node<type>* LHS, Node<type>* RHS)
{
type Solution LHS->getVal() / RHS->getVal();
return new Node<type>(Solution);
}
}
For instance, here, I want to return either a Node<double> if the answer ends up being a decimal, else I want to return a Node<int>. It will return a Node<double> with the solution as Node->Val; And other times, the operation will return an Node<int> (like 4/2) so it will return a Node<int> instead. This is a cut down example of what I want to do but its the same idea.
Polymorphism as intended with virtual methods can't be achieved in C++ if you need different return types.. unless you use something like boost::any or return opaque void *.
For the way C++ works, if you need different return types you need different signatures and hence 2 different methods, however C++ has syntactic sugar for letting the compiler handling that (templates) so that the coder have just to write 1 method once.
template < typename T>
class Node{
//...
};
class Container{
public:
template< typename T>
Node< T> * getNode(){
}
};
a possible implementation:
#include <stack>
#include <string>
#include <typeinfo>
class Container{
std::stack<void *> data;
std::stack<std::string> names;
public:
//push a node on the stack (you have to allocate it)
template< typename T>
void addNode( Node< T> * p){
data.push(static_cast<void*>(p));
names.push(typeid(T).name());
}
template< typename T>
Node< T>* removeNode(){
if(names.top()==typeid(T).name()){
names.pop();
Node< T>* node = reinterpret_cast<Node<T>*>(data.top());
data.pop();
return node;
}
return NULL; //returns nullptr;
}
};
of course, this is just a working example (provided you have Node defined somewhere). To show you a possible way (literally that's the simplest example I can think of, but you can improve performance and use it to design the solution to your problem).
Usage example:
Container c;
Node<double> n1* = new Node<double>(5.0);
Node<double> n2* = new Node<double>(3.0);
Node<int> n3* = new Node<int>(100);
c.addNode(n1);
c.addNode(n2);
c.addNode(n3);
//since I used a stack now I check node in reversed order
cout<< c.getNode<double>() == n3 <<endl; // false! n3 use "int"
cout<< c.getNode<int>() == n3 <<endl; //true!
cout<< c.getNode<double>() == n2 <<endl; //true!
cout<< c.getNode<int>() == n1 <<endl; //false! n1 use double
cout<< c.getNode<double>() == n1 <<endl; //true
delete n1;
delete n2;
delete n3;
I'm trying to teach myself about classes in C++, and I'm running into a bit of a stumbling block, which I can't seem to clear up. I was hoping someone might be able to point me in the correct direction.
I decided to construct a small Tree class, which constructs a new BST. I want to be able to call certain methods on my object like so:
int main() {
Tree<int> tree1;
tree1.insert(5);
int treeMin = tree1.minValue();
int treeMax = tree1.maxValue();
tree1.printTree();
}
Right now, in order to call these functions, I am defining both public and private functions so that you don't call function in a redundant manner. for instance:
(what I'm trying to avoid)
int main() {
Tree<int> tree1;
tree1.insert(tree1, 5);
int treeMin = tree1.minValue(tree1);
int treeMax = tree1.maxValue(tree1);
tree1.printTree(tree1);
}
In order to do avoid having this redundancy, I am defining a public and private version of the same function. In this way, the public functions call their private counterparts.
template<class T>
class Tree {
private:
treeNode<T>* root;
treeNode<T>* newNode(T data);
void insert(treeNode<T>*& root, T data);
int minValue(treeNode<T>*& root);
int maxValue(treeNode<T>*& root);
void printTree(treeNode<T>*& root);
public:
Tree();
~Tree();
void insert(T data);
int minValue();
int maxValue();
void printTree();
};
And then, as an example:
template<class T>
int Tree<T>::minValue() { minValue(root); }
template<class T>
int Tree<T>::minValue(treeNode<T>*& root) {
if (root == NULL) { return 0; }
if (root->left == NULL) { return root->data; }
else { minValue(root->left); }
}
So, my question is:
If I'm writing my functions recursively, I understand that I need to declare a private function that accepts an argument, but is this considered a bad style? Is this sloppy?
Thanks for your help!
The private member functions in your code are only a needless complication. I would just move their code to the public member functions: less code, more clean code, less indirection so more directly grokable code, all nice. For some of them you might support reuse by making them free functions in a details namespace, but I think that would be premature generalization, expending effort on possible reuse that probably won't take place.
Example code at end of answer.
Re another design issue, declaring
int minValue();
int maxValue();
precludes calling these member functions on a const object. Instead do
int minValue() const;
int maxValue() const;
A third issue, it's generally a Really Bad Idea™ to do i/o in a non-i/o class. If you print the tree to standard output, how would you use the class in a GUI program? So, instead of
void printTree();
do e.g.
ostream& operator<<( ostream& stream ) const;
or e.g.
string toString() const;
A fourth issue, you need to take charge of copying – read up on the “rule of three” and the “rule of zero”.
The simplest way to do that is to replace
treeNode<T>* root;
with
unique_ptr< treeNode< T > > root;
where unique_ptr is std::unique_ptr.
Alternatively declare at least a copy constructor and a copy assignment operator, or inherit from a “non-copyable” class. To make the class effectively non-copyable, you can make these operators private or protected. To make it copyable, make them public and do the right thing in each (a good default implementation of the copy assignment operator is to express it in terms of copy construction via the copy-and-swap idiom, which means introducing a non-throwing swap function).
A fifth issue is that the implementation
template<class T>
int Tree<T>::minValue(treeNode<T>*& root) {
if (root == NULL) { return 0; }
if (root->left == NULL) { return root->data; }
else { minValue(root->left); }
}
strongly suggests that each node stores a value that's implicitly convertible to int. You don't provide the declaration of treeNode. But this looks like a design level bug, that the intent was for minValue to return a T, not an int – and ditto for maxValue.
A very small coding issue (not design level): in C++11 and later you should preferentially use nullptr, not NULL.
nullptr can be freely passed through argument forwarding functions, while NULL then suffers a decay to integral type, since NULL is just a zero-constant of integral type.
nullptr does not require that you include any header, while NULL is defined by a header, i.e. with nullptr you avoid a header dependency.
Finally, regarding
if (root == NULL) { return 0; }
for the minValue, this may of course be the intention, the design. But possibly you want to either signal failure or treat the call as a logic error.
To treat the call as an error, assert( root != nullptr ); and provide a means for the client code to check for empty tree.
To signal failure, either return an object with optional value (e.g. like boost::optional or Barton/Nackmann's original Fallible), or throw an exception (the std::runtime_error class is a good general default exception class choice).
It's also possible to combine the two approaches, to provide both, perhaps with names like minValue and minValueOrX.
More generally it's sometimes possible to reserve some special value as a "no such" indicator. E.g. std::numeric_limits<T>::min(). But this makes for brittle code, since such a value can easily occur naturally in the data, and since client code may easily fail to check for the special value.
Example, coded for C++11:
#include <assert.h>
#include <iostream> // std::cout, std::endl
#include <string> // std::string
namespace my {
using std::string;
template<class T>
class Tree
{
private:
struct Node
{
T value;
Node* p_left;
Node* p_right;
auto to_string() const -> string
{
using std::to_string;
string const left = (p_left == nullptr? "" : p_left->to_string());
string const right = (p_right == nullptr? "" : p_right->to_string());
return "(" + left + " " + to_string( value ) + " " + right + ")";
}
~Node() { delete p_left; delete p_right; }
};
Node* root_;
Tree( Tree const& ) = delete;
Tree& operator=( Tree const& ) = delete;
public:
auto is_empty() const -> bool { return (root_ == nullptr); }
void insert( T const data )
{
Node** pp = &root_;
while( *pp != nullptr )
{
auto const p = *pp;
pp = (data < p->value? &p->p_left : &p->p_right);
}
*pp = new Node{ data, nullptr, nullptr };
}
auto minValue() const -> T
{
assert( root_ != nullptr );
Node* p = root_;
while( p->p_left != nullptr ) { p = p->p_left; }
return p->value;
}
auto maxValue() const -> T
{
assert( root_ != nullptr );
Node* p = root_;
while( p->p_right != nullptr ) { p = p->p_right; }
return p->value;
}
auto to_string() const -> string
{
return (root_ == nullptr? "" : root_->to_string());
}
~Tree() { delete root_; }
Tree(): root_( nullptr ) {}
Tree( Tree&& other ): root_( other.root_ ) { other.root_ = nullptr; }
};
} // namespace my
auto main() -> int
{
my::Tree<int> tree;
for( int const x : {5, 3, 4, 2, 7, 6, 1, 8} )
{
tree.insert( x );
}
using std::cout; using std::endl;
cout << tree.to_string() << endl;
cout << "min = " << tree.minValue() << ", max = " << tree.maxValue() << endl;
}
Output:
(((( 1 ) 2 ) 3 ( 4 )) 5 (( 6 ) 7 ( 8 )))
min = 1, max = 8