带有重载ostream和两个类的二叉树文件

时间:2017-03-18 01:59:28

标签: c++ c++11 operator-overloading binary-tree fstream

我想将二叉树保存到txt文件中。这就是我所拥有的

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

然后是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);
}

想法是重载运算符&lt;&lt;对于Node,然后在zapisDoSouboru中使用递归并将其保存为Node by Node。不幸的是它不起作用。 有谁知道,问题在哪里? 谢谢你的帮助

EDIT 在

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);
    }
}

我改变了整个递归,但现在看起来它有效,但它不会在文件中写任何东西。不是f的引用吗?该文件打开和关闭,zapis()遍历所有节点。

1 个答案:

答案 0 :(得分:0)

在函数zapisDoSouboru中,您需要检查子节点是否为nullptr,否则它将在到达叶节点时发生段错误。

以下是修改后的版本: 模板

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);
    }
}


您为节点定义的运算符也未被编译器选中。 这是运营商的代码:

template<typename T>
ostream& operator<<(ostream &os, Node<T> &n){
    os << n->data;
    return os;
}

变量n它是通过引用传递的,并且您正在使用需要指针的->来访问它。代码编译的原因是因为当您调用f << r时实际上使用Node<T>*调用运算符,因此编译器不使用期望Node<T>&的模板函数。这意味着模板函数永远不会被实例化。

我认为在这种情况下不需要让操作员过载。您只需致电r->getData()

即可

在查看代码时我注意到的一般事项:

  • 我会尝试使用unique_ptr
  • 我会尽量避免使用朋友类
  • 我会重构代码,以便在每次递归调用时都不打开和关闭文件

如果您需要任何澄清,请告诉我