I would like to save my binary tree to txt file. Here's what I have
qt.h
#ifndef QT_H_INCLUDED
#define QT_H_INCLUDED
#include<iostream>
using namespace std;
template<typename T>
class Node{
T data;
Node<T> *left;
Node<T> *right;
public:
Node(T d) : data(d), left(nullptr), right(nullptr){}
void print(){
cout << data << endl;}
T getData()const {
return data;
}
void setData(const T &value){
data = value;
}
template<typename X> friend class Tree;
template<T> friend ostream& operator<<(ostream &os, Node &n);
};
template<typename T>
ostream& operator<<(ostream &os, Node<T> &n){
os << n->data;
return os;
}
#endif // QT_H_INCLUDED
then tree.h
#ifndef TREE_H_INCLUDED
#define TREE_H_INCLUDED
#include "qt.h"
#include <fstream>
#include <iostream>
namespace std;
template<typename T>
class Tree{
Node<T> *root;
void insertIntoTree(T &d, Node<T> *&r);
void printTree(Node<T> *r);
void deleteTree(Node<T> *&r);
Node<T>* findInTree(T &d, Node<T> *r, Node<T> *&parent);
void deleteLeaf(Node<T> *p, Node<T> *q);
void deleteInBranch(Node<T> *p, Node<T> *g);
void zapisDoSouboru(Node<T> *r);
public:
Tree() : root(nullptr){}
~Tree(){
clean();
}
bool find(T d){
Node<T> *dummy=nullptr;
return findInTree(d, root, dummy);
};
void clean(){
deleteTree(root);}
void insert(T d){
insertIntoTree(d, root);}
void print(){
printTree(root);
}
bool deleteNode(T d);
void zapis(){
zapisDoSouboru(root);
}
}
template<typename T>
void Tree<T>::zapisDoSouboru(Node<T> *r){
fstream f;
f.open("mytext.txt", ios_base::app);
if(r){
f << r;
}
f.close();
zapisDoSouboru(r->left);
zapisDoSouboru(r->right);
}
the idea was to overload operator<< for Node and then use recursion in zapisDoSouboru and save it Node by Node. Unfortunately it does not work.
Does anybody know, where the problem is?
Thank you for helping
EDIT
in
class Tree{
void zapis(ostream& f, Node<T> *r);
public:
void zapisDoSouboru(){
fstream f;
f.open("mytext.txt", ios_base::app);
zapis(f, root);
f.close();
}
}
template<typename T>
void Tree<T>::zapis(ostream& f,Node<T> *r){
if(r){
zapis(f, r->left);
f << r;
zapis(f, r->right);
}
}
I changed the whole recursion, but now it looks like it works, but it doesnt write anything in the file. Isnt the reference to f wrong? The file opens and close, zapis() goes through all nodes.
In the function zapisDoSouboru you need to check if the child nodes are nullptr otherwise it will segfault whenever it reaches the leaf nodes.
Here is the modified version:
template
void Tree<T>::zapisDoSouboru(Node<T> *r){
fstream f;
f.open("mytext.txt", ios_base::app);
if(r){
f << r;
}
f.close();
if(nullptr != r->left) {
zapisDoSouboru(r->left);
}
if(nullptr != r->right) {
zapisDoSouboru(r->right);
}
}
Also the operator you have defined for node it is not being picked up by the compiler.
This is the piece of code of your operator:
template<typename T>
ostream& operator<<(ostream &os, Node<T> &n){
os << n->data;
return os;
}
The variable n it is passed by reference and you are accessing it with -> which expects a pointer. The reason why the code compiles is because when you call f << r you actually call the operator with a Node<T>* so the compiler does not use the template function which expects a Node<T>&. Which means the template function is never instantiated.
I think there is not much need for having the operator overload in this case. You can just simply call r->getData()
Also general things i noticed while looking at the code:
I would try to use unique_ptr
I would try to avoid using friend classes
I would refactor the code to not open and close the file at every recursive call
Let me know if you need any clarifications
Related
I'm trying to make InOrder in void-type, which executes in-order traversal in a binary search tree.
//Code Provided by Professor
//Program 5.1:Inorder traversal of a binary tree
//===============================================
template <class T>
void Tree<T>::Inorder()
{// Driver.
Inorder(root);
}
template <class T>
void Tree<T>::Inorder(TreeNode<T> *currentNode)
{// Workhorse.
if (currentNode) {
Inorder(currentNode->leftChild);
Visit(currentNode);
Inorder(currentNode->rightChild);
}
}
The above code is provided by Professor, as a reference making my own InOrder function.
This Code is how I declared the elements(requisites) for my binary search tree.
#include <iostream>
using namespace std;
template<class K, class E>
class BinarySearchTree
{
public:
virtual void Insert(const pair<K, E>&) = 0;
virtual void Delete(const K&) = 0;
virtual pair<K, E>*Get(const K&) const = 0;
virtual void InOrder()const;
};
template<class T>
struct TreeNode {
T data;
TreeNode<T> *leftChild;
TreeNode<T> *rightChild;
TreeNode(T node) : data(node), leftChild(0), rightChild(0) {}
};
template<class K, class E>
class BST : BinarySearchTree<K, E> {
public:
BST() : root(0) {}
void Insert(const pair<K, E>&);
void Delete(const K&);
pair<K, E>*Get(const K&)const;
void InOrder()const;
private:
TreeNode<pair<K, E>> *root;
};
Other functions work well, and I would appreciate any help with making InOrder function, using C++.
The concept of in order is just the concept of order. You must also say what should be done in that order. The code provided by your professor calls a visit function.
That means that in your implementation, you also need such a visit function. It can either be hardcoded (display a node on cout) or better passed as a parameter. In that case, you should declare InOrder as:
void InOrder(void (*visit)(const pair<K, E>&))const;
And later call it (for example with a lambda function) as:
BST<int, string> bst;
...
bst.InOrder([](const pair<int, string>&ke) {
cout << "K: " << ke.first << " -E: " << ke.second << "\n";
});
A possible implementation mimicing your professor's code could be:
template<class K, class E>
void BST<K,E>::doInOrder(const TN* root, void (*visit)(const pair<K, E>&)) {
if (root) {
doInOrder(root->leftChild, visit);
visit(root->data);
doInOrder(root->rightChild, visit);
}
}
template<class K, class E>
void BST<K,E>::InOrder(void (*visit)(const pair<K, E>&))const {
doInOrder(root, visit);
}
Everything was working before I introduced templates to my code
EDIT:
Here is the problem to which I was able to narrow it down, thanks to your tips:
In file included from main.cpp:4:
stack.cpp: In member function void Stack<TYPE>::push(Stack<TYPE>&, TYPE)':
stack.cpp:35: error:node' is not a type
I wonder if a similar problem could appear later in the pop function, but it seems like it does not.
I'm confused as to why it seems to insist that node is not a type.
EDIT#2:
this statement in the main.cpp file is now causing trouble. I have moved all the definitions out of stack.cpp to stack.h. After this Stack<int> list;my compiles says Segmentation fault (core dumped).
stack.h:
#include <iostream>
using namespace std;
template <typename TYPE>
struct node {
TYPE data;
node<Type> *next;
node(){
data = NULL;
next = NULL;
}
~node(){
if (data!=0)
delete next;
}
explicit node(int i){
data = i;
}
};
template <typename TYPE>
class Stack {
private:
node<TYPE> *top;
void init();
public:
Stack(); // default constructor
virtual ~Stack(); // destructor
bool empty();
void push(Stack&,TYPE);
TYPE pop(Stack&);
int peek();
void clear();
ostream& printf(ostream&, node<TYPE> *);
ostream& print(ostream&);
ostream& sequentialPrint(Stack&,ostream&);
ostream& reversePrint(Stack&,ostream&);
friend ostream& operator<<(ostream&, Stack&);
};
stack.cpp:
template <typename TYPE>
void Stack<TYPE>::push(Stack<TYPE> &s, TYPE i) {
node<TYPE> * n = new node(i);
n->next = top;
top = n;
}
template <typename TYPE>
TYPE Stack<TYPE>::pop(Stack<TYPE> &s){
if (empty()) {
cerr<<"Stack is empty \n";
}
TYPE temp = s.top->data;
top = top->next;
return temp;
}
friend ostream& operator<<(ostream&, Stack&); is not needed
you can't define template methods in cpp file. Every element of template which is template parameter depended must be defined in header file.
I have a binary search tree class (BST.h) and a node class (Node.h) of which works fine when I store data types such as integers in it. My problem is trying store class objects in my BST and use an attribute from the object as the key. My program also has a student class which contains studentID and studentName. How would I write an operator overload in my student class so every time my BST preforms operation on nodes, it will overload to the student.getID(), instead of operating on the object itself. I have the rough idea of what the overload function should look like but i don't know where it should go or if its coded correctly anyway.
//My attempt at an operator overload
bool operator< (const Student &s1, const Student &s2)
{
return s1.GetID < s2.GetID;
}
//Node.h
#ifndef NODE_H
#define NODE_H
#include <iostream>
using namespace std;
template<class T>
class Node
{
public:
Node();
T data;
Node *left;
Node *right;
Node(T);
};
template<class T>
Node<T>::Node()
{
}
template<class T>
Node<T>::Node(T d)
{
data = d;
left = NULL;
right = NULL;
}
#endif //
//BST.h
#ifndef BST_H
#define BST_H
#include <iostream>
#include "Node.h"
#include <string>
using namespace std;
template<class T>
class BST
{
public:
BST();
void Insert(T);
Node<T> *Search(T);
void preOrder();
void inOrder();
void postOrder();
~BST();
private:
Node<T> *root;
void Insert(T , Node<T> *aNode);
Node<T> *Search(T, Node<T> *aNode);
void preOrder(Node<T> *aNode);
void inOrder(Node<T> *aNode);
void postOrder(Node<T> *aNode);
};
template<class T>
BST<T>::BST()
{
root = NULL;
}
template<class T>
void BST<T>::Insert(T data, Node<T> *aNode)
{
if (data < aNode->data)
{
if (aNode->left != NULL)
{
Insert(data, aNode->left);
}
else
{
aNode->left = new Node<T>(data);
aNode->left->left = NULL;
aNode->left->right = NULL;
}
}
else
{
if (data >= aNode->data)
{
if (aNode->right != NULL)
{
Insert(data, aNode->right);
}
else
{
aNode->right = new Node<T>(data);
aNode->right->left = NULL;
aNode->right->right = NULL;
}
}
}
}
template<class T>
void BST<T>::Insert(T data)
{
if (root != NULL)
{
Insert(data, root);
}
else
{
root = new Node<T>(data);
root->left = NULL;
root->right = NULL;
}
}
template<class T>
Node<T>* BST<T>::Search(T data, Node<T> *aNode)
{
if (aNode != NULL)
{
if (data == aNode->data)
{
return aNode;
}
if (data < aNode->data)
{
return Search(data, aNode->left);
}
else
{
return Search(data, aNode->right);
}
}
else
{
return NULL;
}
}
template<class T>
Node<T>* BST<T>::Search(T data)
{
return Search(data, root);
}
template<class T>
void BST<T>::preOrder()
{
preOrder(root);
}
template<class T>
void BST<T>::preOrder(Node<T> *aNode)
{
if (aNode != NULL)
{
cout << aNode->data << " ";
preOrder(aNode->left);
preOrder(aNode->right);
}
}
template<class T>
void BST<T>::inOrder()
{
inOrder(root);
}
template<class T>
void BST<T>::inOrder(Node<T> *aNode)
{
if (aNode != NULL)
{
inOrder(aNode->left);
cout << aNode->data << " ";
inOrder(aNode->right);
}
}
template<class T>
void BST<T>::postOrder()
{
postOrder(root);
}
template<class T>
void BST<T>::postOrder(Node<T> *aNode)
{
if (aNode != NULL)
{
postOrder(aNode->left);
postOrder(aNode->right);
cout << aNode->data << " ";
}
}
template<class T>
BST<T>::~BST()
{
}
#endif // !BST_H
//Student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
#include <string>
using namespace std;
class Student
{
public:
Student();
Student(string, int);
~Student();
int Student::GetID();
private:
string name;
int ID;
};
inline int Student::GetID()
{
return ID;
}
You seem to be asking about operator< taking Students , however Student is not a class template, so the title of your post is baffling.
As someone else pointed out, your operator< is almost correct, except you have to actually call GetID() instead of comparing pointers to member functions.
This won't work yet until you fix GetID however. Instead of int Student::GetID(); it should be:
int GetID() const;
The const means that it can be called on objects passed by const reference, as you have in your operator< implementation. And you don't repeat the Student:: when declaring functions inside the class. (You use it when defining class members outside of the class definition).
Declare it as a friend function within your Student class, next to the rest of your member functions
friend bool operator < (Student& s1, Student& s2);
Your implementation is correct, it should go outside your Student class within the same header file.
I have a this Tree Class:
#include <fstream>
using namespace std;
#ifndef HUFF_TREE_H
#define HUFF_TREE_H
class HuffTree{
public:
HuffTree();
HuffTree(char data, float frequency);
~HuffTree();
HuffTree& operator = (const HuffTree& tree);
int getNumberNodes();
float getFrequency();
void merge(HuffTree *tree);
friend ostream& operator << (ostream &out, const HuffTree &tree);
private:
struct node{
char data;
float frequency;
node* left;
node* right;
};
node* head;
int number_nodes;
float avg_code_length;
void destroy(node* &head);
void copyTree(node* &t1, node* t2);
};
#endif
Here is the code for the overloaded output operator:
ostream& operator << (ostream &out, const HuffTree &tree){
out << "testing";
return out;
}
In my main function, I call function as follows:
HuffTree* tree;
cout << tree;
From what I have read, this should work, but I am getting hexadecimal numbers printed to the screen. The above example prints out "0x1dcc2b0". The same thing happens if I pass it a file handle. I think I just need a fresh pair of eyes here, can anyone see my problem?
Since tree is a pointer, you're outputting a pointer.
Instead, you want to do this:
cout << *tree
Here's a template (queue) I'm trying to write:
#include <iostream>
using namespace std;
template <typename T>
class Queue
{
friend ostream& operator<< (ostream &, const Queue<T> & );
private:
template<class> class Node;
Node<T> *front;
Node<T> *back;
public:
Queue() : front(0), back(0) {}
~Queue();
bool Empty()
{
return front == 0;
}
void Push(const T& NewEl)
{
Node<T&> *El = new Node<T> (NewEl);
if (Empty())
front=back=El;
else
{
back-> next = El;
back = El;
}
}
void Pop()
{
if (Empty())
cout << "Очередь пуста." << endl;
else
{
Node<T> *El = front;
front = front -> next;
delete El;
}
}
void Clear()
{
while (! Empty())
Pop();
}
};
template <typename T>
class Node
{
friend class Queue<T>;
public:
Node() {next = 0;}
Node(T nd) {nd=node; next=0;}
T& getsetnode(){return node;}
Node<T>*& getsetnext(){return next;}
private:
T front;
T back;
T node;
Node<T> *next;
};
template <class T> ostream& operator<< (ostream &, const Queue<T> & );
int main()
{
Queue<int> *queueInt = new Queue<int>;
for (int i = 0; i<10; i++)
{
queueInt->Push(i);
cout << "Pushed " << i << endl;
}
if (!queueInt->Empty())
{
queueInt->Pop();
cout << "Pop" << endl;
}
queueInt->Front();
queueInt->Back();
queueInt->Clear();
cout << "Clear" << endl;
return 0;
}
At these lines:
Node<T&> *El = new Node<T> (NewEl);
front = front -> next;
delete El;
I get Implicit instantiation of undefined template 'Queue<int>::Node<int>'. What am I doing wrong? After reading this post I tried changing int to const int to see if that was the problem, but apparently it isn't, because I get the same error.
I'm using XCode with LLVM compiler 4.2. When I switch to GCC I get more errors:
template<class> class Node; gets Declaration of 'struct Queue<int>::Node<int>',
Node<T&> *El = new Node<T> (NewEl); gets Invalid use of incomplete type,
and anything dealing with assignment of anything to El can't convert <int&>* to <int>* (but deleting reference doesn't change anything for LLVM).
template <typename T>
class Queue
{
private:
template<class> class Node;
/* ... */
This is a forward declaration of Queue::Node. The latter defined class Node is in the global namespace, so they aren't the same and any usage of Queue::Node will result in an incomplete-type error. Since you don't provide an interface to the interior nodes anyway just scrap the global definition of Node and stick it into Queue:
template <typename T>
class Queue
{
private:
class Node
{
public:
Node() {next = 0;}
/* ... */
};
/* ... */
};