2017-03-18 10 views
0

バイナリツリーをtxtファイルに保存したいと思います。ここでは、tree.hオーバーロードされたostreamと2つのクラスを持つバイナリツリーファイル

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

アイデアはノードのオペレータ< <をオーバーロードし、その後zapisDoSouboruで再帰を使用して、ノード毎にそれを保存することでした私は

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 

を持っているものです。残念ながら、それは動作しません。 誰かが知っていますか、どこに問題がありますか? は、私は全体の再帰を変更

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

にEDIT

ご協力いただきありがとうございますが、それが動作するようになりました、それは見えますが、それはファイルに何かを書くdoesntの。 Is notはfを間違って参照していますか?ファイルが開いたり閉じたりすると、zapis()はすべてのノードを通過します。

+0

[よくある質問](http://stackoverflow.com/help/how-to-ask)を参照してください。 何がうまくいかないのかを明確に指定していないと、助けが不可能です。 – mcrlc

答えて

0

関数zapisDoSouboruでは、子ノードがnullptrであるかどうかをチェックする必要があります。それ以外の場合は、リーフノードに到達するたびにsegfaultします。ここで

修正したバージョンです: テンプレート

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>&を必要とするテンプレート関数を使用しないためです。つまり、テンプレート関数はインスタンス化されません。

この場合、オペレータが過負荷になる必要はあまりないと思います。私はリファクタリングでしょう、私は友人のクラス

  • を使用しないようにしようと、私は
  • をunique_ptrを使用しようとする

    • :あなたは、単にまた、コードを見ながら、私は気づいた一般的なものをr->getData()

      を呼び出すことができますすべての再帰呼び出しでファイルを開いたり閉じたりしないコード

    説明が必要な場合はお知らせください

  • +0

    ありがとう、私はuniqe_ptrを見てください –

    +0

    今私は友人のクラスや再帰的な呼び出しを避けることはできません、それは学校の仕事ですが、私はそれを私の心の中に保つでしょう。私は再びそれを行った、演算子の過負荷の間違いは<<今私には明らかです。 zapisDoSouboruの再帰呼び出しで、別の方法で書きました –

    関連する問題