在 ostream 函数中使用递归函数作为输出 [英] Using a recursive function as output in a ostream function

查看:49
本文介绍了在 ostream 函数中使用递归函数作为输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在重载 ostream 运算符 <<能够打印或写下我的目标.在其中之一中,我实际上是在 file.txt 中写入我的整个结构.结构对象实际上是一棵二叉树,为了确保我从中获取每个元素,我需要一个递归函数.这是我正在尝试做的基本代码.

I'm overloading the ostream operator << to be able to print out or write down my ojbects. In one of these, I'm actually writting my whole structure inside a file.txt. The structure object is actually a binary tree and to make sure I'm getting every element out of it I need a recursive function. Here is a basic code of what I'm trying to do.

out << parcour(tree); // recursive function

Parcour 假设返回另一个结构,其中我有要写入输出文件的信息.我的递归函数的内部是这样的:

Parcour is suppose to return anoter structure in which I have the informations to write in the output file. The inside of my recursive function goes something like this:

node* parcour(node* node){
      if (node) {
         parcour(childnode(0));
         parcour(childnode(1));
         return node;
      }
   return nullptr;
}

这个函数返回所有包含我想要的信息的节点.所以我认为问题是将多个返回到一个 std::cout 中实际上是行不通的.我想知道是否可以将具有多个返回的函数(递归函数)作为输出,每次返回一个.

All the node with the informations I want are returned by this function. So I think the problem is that multiple returns into one single std::cout isn't actually working. I would like to know if there is anyway that a function with multiple return (a recursive function) could be taken as an ouput where every single return will be done one at a time.

请不要注意语法错误,因为我的代码运行完美,除了我无法解决的单个概念.

Please don't pay attention to syntaxt error since my code is running perfectly except for that single concept that I can't resolve.

有些人一直要求我提供更多代码,所以基本上我只会复制粘贴下面的原始代码(注意:一切都是法语:S):

Some people have been requesting me to give more code so basically I'll just copy paste the ORIGINAL CODE beneath(note: everything is in french :S):

这是 Arbres.h

This is Arbres.h

 #ifndef ARBRES_H
#define ARBRES_H
#pragma once
#include <iostream>
#include <vector>
using namespace std;

// noeud pour un arbre binaire contenant des informations de type T
template <class T>
class Noeud
{
private:
    T* element; // élément du noeud
    Noeud<T> *parent; // Pointeur vers le parent
    Noeud<T> *gauche; // Pointeur vers le fils gauche
    Noeud<T> *droit; // Pointeur vers le fils droit

public:

//constructeur du noeud
    Noeud()
    {
        element = nullptr;
        parent = nullptr;
        gauche = nullptr;
        droit = nullptr;
    }

// destructeur du noeud
    ~Noeud ()
    {

    }

// retourne l'enfant où "i" represente la position de l'enfant (droit ou gauche)
    Noeud<T> * Enfant(int i) const
    {
        if (i == 0)
            if (!gauche)
                return nullptr;
            else
                return gauche;
        else if (i == 1)
            if (!droit)
                return nullptr;
            else
                return droit;
        else
            return nullptr;
    }

// retourne le parent du noeud
    Noeud<T> *Parent () const
    {
        return parent;
    }

// retourne un pointeur vers l'élément du noeud (les infos)
    T *Element() const
    {
        return element;
    }

// modifie la valeur de l'élément
    void RemplacerElement( T *ele )
    {
        element = ele;
    }

//retourne vrai si le noeud est une feuille
    bool EstUneFeuille () const
    {
        return (!gauche) && (!droit);
    }

//retourne vrai si le noeud est une racine
    bool EstUneRacine () const
    {
        return (!parent);
    }

// détache l'enfant du noeud et retourne un pointeur vers ce noeud
    Noeud<T> *Detacher (Noeud<T>* Enfant)
    {
        Noeud<T> *temp;

        if (Enfant->parent->gauche == Enfant) {
            temp = Enfant->parent->gauche;
            Enfant->parent->gauche = nullptr;
        } else if (Enfant->parent->droit == Enfant) {
            temp = Enfant->parent->droit;
            Enfant->parent->droit = nullptr;
        } else
            return nullptr;
        return temp;
    }

// attache le noeud à l'enfant. Retourne vrai si l'opération est réussie
    bool Attacher(Noeud<T>* nouvelEnfant)
    {
        if (!gauche)
            gauche = nouvelEnfant;
        else if(!droit)
            droit = nouvelEnfant;
        else
            return 0;
        return 1;
    }

// attache les enfants au noeud. Retourne vrai si l'opération est réussie
    bool Attache(Noeud<T>* noeudCourant)
    {
        if (!gauche->parent)
            gauche->parent = noeudCourant;
        else if (!droit->parent)
            droit->parent = noeudCourant;
        else
            return 0;
        return 1;
    }

// Fonction Récursive qui crée un nouveau noeud et le place correctement dans l'arbre
    void CreerNouveauNoeud(istream& in, Noeud<T>* noeudCourant, int val) {
        if (val == 1) {
            if (!noeudCourant->Enfant(0)) {
                noeudCourant->Attacher(new Noeud<T>());
                noeudCourant->Attache(noeudCourant);
                noeudCourant = noeudCourant->Enfant(0);
                noeudCourant->RemplacerElement(new T());
                in >> *(noeudCourant->Element());
                return;
            }
            else if (!noeudCourant->Enfant(1)) {
                noeudCourant->Attacher(new Noeud<T>());
                noeudCourant->Attache(noeudCourant);
                noeudCourant = noeudCourant->Enfant(1);
                noeudCourant->RemplacerElement(new T());
                in >> *(noeudCourant->Element());
                return;
            }
            else {
                cout << "\nERROR: Structure dans le fichier texte incorrect (limite de 2 sous-noeuds par noeud)" << endl;
                return;
            }
        }
        else {
            if (!noeudCourant->Enfant(1)) // S'il existe un noeud à droite s'est qu'on est rendu à ajouter la, sinon on va à gauche
                CreerNouveauNoeud(in, noeudCourant->Enfant(0), val - 1);
            else
                CreerNouveauNoeud(in, noeudCourant->Enfant(1), val - 1);
        }
        return;
    }

// le mot clé "friend" indique que la fonction peut utiliser les membres privés de la classe Noeud
    template<class U>
    friend istream& operator>> (istream& in, Noeud<U>& n);

    template<class U>
    friend ostream& operator<< (ostream& out, Noeud<U>& n);

};

// surcharge de l'opérateur >> pour un noeud
template <class T>
istream& operator>> (istream& in, Noeud<T>& n)
{
    in >> *n.element;
    return in;
}

// surcharge de l'opérateur << pour un noeud
template <class T>
ostream& operator<< (ostream& out, Noeud<T>& n)
{
    out << *n.element;
    return out;
}


// Patron de classe définissant la classe "Arbres"
// contenant des informations de type T
template <class T>
class Arbres
{
// Patron de classe définissant la classe "Arbres"
private:
    vector<Noeud<T>*> racines;
    Noeud<T>* noeudCourant;

public:

//constructeur d'une classe Arbres
    Arbres()
    {
        noeudCourant = nullptr;
    }

// destructeur d'une classe Arbres
    ~Arbres ()
    {
        supprimeArbre();
    }

    // ajoute un arbre de niveau 0 (un noeud) à la liste des racines
    int NouveauNoeud(Noeud<T>* n)
    {
        n->RemplacerElement(new T());
        racines.push_back(n);
        return racines.size() - 1;
    }

    // positionne le noeud courant sur le noeud racine d'indice i
    void SetCourant(int i)
    {
        if(i<racines.size())
            noeudCourant = racines[i];
    }

    // Déplace le noeud courant vers son enfant i
    void NaviguerVersEnfant(int i)
    {
        noeudCourant = noeudCourant->Enfant(i);
    }

    // Déplace le noeud courant vers son parent
    void NaviguerVersParent()
    {
        noeudCourant = noeudCourant->Parent();
    }

    // mets le noeud en position i de la liste racine comme enfant du noeud courant
    void joindreCourant(int i)
    {
        if (!noeudCourant->Enfant(0) || !noeudCourant->Enfant(1)) {
            noeudCourant->Attacher(racines[i]);
            racines[i] = nullptr;
            racines.erase(racines.begin()+i);
        }
        else {
            cout << "/nERROR: Aucun Enfant disponible sur le noeud Courant " << endl;
        }
    }

    // Détache le noeud courant de son parent
    void DetacherCourant()
    {
        if (noeudCourant->Parent()->Enfant(0) == noeudCourant) {
            noeudCourant->Detacher(noeudCourant->Enfant(0));
        }
        else
            noeudCourant->Detacher(noeudCourant->Parent()->Enfant(1));
    }

    // supprime le noeud courant
    void SupprimerCourant()
    {
        supprimeArbre(noeudCourant);
    }

    // retourne la liste des noeuds racines
    const vector<Noeud<T>*>* getRacine() const
    {
        return &racines;
    }

    // retourne le noeud courant
    const Noeud<T>* getCourant() const
    {
        return noeudCourant;
    }

    // fonction récursive qui parcours l'arbre et retourne chacun d'entre eux
    void parcourir(ostream& out, Noeud<T>* racine) {
        if (racine) {
            parcourir(out, racine->Enfant(0));
            parcourir(out, racine->Enfant(1));
            out << *racine;
        }
        return;
    }

    void supprimeArbre(Noeud<T>* racine) { // fonction récursive qui parcours l'arbre et supprime chaque noeud que l'on rencontre
        if (racine) {
            supprimeArbre(racine->Enfant(0));
            supprimeArbre(racine->Enfant(1));
            delete racine->Element();
            delete racine;
        }
        return;
    }

// le mot clé "friend" indique que la fonction peut utiliser les membres privés d'une classe Arbres
    template<class U>
    friend istream& operator>> (istream& in, Arbres<U>& n);

    template<class U>
    friend ostream& operator<< (ostream& out, Arbres<U>& n);

};

// surcharge de l'opérateur >> pour un objet de type Arbres<T>
template <class T>
istream& operator>> (istream& in, Arbres<T>& n)
{
    string buffer;
    while (in >> buffer) {
        int a = count(buffer.begin(), buffer.end(), '-'); // Compte le nombre de tiret pour déterminer le niveau du noeud dans l'arbres
        if (a == 0) {
            n.SetCourant(n.NouveauNoeud(new Noeud<T>()));
            n.noeudCourant->RemplacerElement(new T());
            in >> *(n.noeudCourant);
        }
        else {
            n.noeudCourant->CreerNouveauNoeud(in, n.noeudCourant, (a / 2));
        }
    }
    return in;
}

// surcharge de l'opérateur << pour un objet de type Arbres<T>
template <class T>
ostream& operator<< (ostream& out, Arbres<T>& n) 
{
    for (int x = 0; x < n.racines.size(); x++) {
        n.parcourir(out, n.racines[x]);
    }
    return out;
}

#endif

这是 TP2.h

#ifndef TP2_H
#define TP2_H
#pragma once
# include <string>
# include <iostream>
using namespace std;

class Personne
{
    private:
        string nom;
        string prenom;
        int age;
        string metier;
    public:
        Personne();
        Personne(string leNom, string lePrenom, int lAge, string leMetier);
        ~Personne();

        friend istream& operator>> (istream& in, Personne& n);
        friend ostream& operator<< (ostream& out, Personne& n);
};

#endif

这是 TP2.cpp

#include "TP2.h"
#include "Arbres.h"
#include <fstream>
#include <algorithm>
using namespace std;

Personne::Personne() {
    return;
}

Personne::Personne(string leNom, string lePrenom, int lAge, string leMetier)
{
    nom = leNom;
    prenom = lePrenom;
    age = lAge;
    metier = leMetier;
    return;
}

Personne::~Personne()
{
    return;
}

istream& operator>> (istream& in, Personne& n)
{
    in >> n.nom >> n.prenom >> n.age >> n.metier;
    return in;
}

ostream& operator<< (ostream& out, Personne& n)
{
    out << "\tNom: " << n.nom << "\n\tPrenom: " << n.prenom << "\n\tAge: " << n.age << "\n\tMetier: " << n.metier << endl;
    return out;
}

int main(){
    ifstream Transaction;
    ifstream Data_input;
    ofstream Data_ouput;
    string transaction_fichier;
    string arbres_fichier;
    char op[1], FILENAME[50]; // Operateur, Nom d'un fichier
    int i; // Indice
    Arbres<Personne>* structure = nullptr;
    cout << "Entrer le nom du fichier transaction: ";
    cin >> transaction_fichier; // IMPORTANT : Le nom du fichier ne doit pas compoter d'espace!
    cout << endl;
    Transaction.open(transaction_fichier);
    if (Transaction.fail())
        cout << "\nError 404 : File not found\n";
    while (!Transaction.eof()) {
        Transaction >> op;
        switch (op[0]) {
        case '*':
            Transaction >> *(*(structure->getRacine()))[structure->NouveauNoeud(new Noeud<Personne>())];
            break;
        case '&':
            Transaction >> i;
            structure->SetCourant(i);
            break;
        case '>':
            Transaction >> i;
            structure->NaviguerVersEnfant(i);
            break;
        case '<':
            Transaction >> i;
            structure->NaviguerVersParent();
            break;
        case '+':
            Transaction >> i;
            structure->joindreCourant(i);
            break;
        case '-':
            structure->DetacherCourant();
            break;
        case '!':
            structure->SupprimerCourant();
            break;
        case '%':
            cout << "Informations des personnes dans les noeuds racines:" << endl;
            for (unsigned int x = 0; x < (*(structure->getRacine())).size(); x++) {
                cout << *(*(structure->getRacine()))[x] << endl;
            }
            break;
        case '?':
            cout << "Informations de la personne dans le noeud courant:" << endl;
            cout << *(structure->getCourant()->Element()) << endl;
            break;
        case '#':
            if (structure) {
                for (unsigned int x = 0; x < (*(structure->getRacine())).size(); x++) {
                    structure->supprimeArbre((*(structure->getRacine()))[x]);
                }
            }
            else {
                Transaction >> FILENAME;
                Data_input.open(FILENAME);
                if (Data_input.fail())
                    cout << "\nError 404 : File not found\n";
                structure = new Arbres<Personne>;
                Data_input >> *structure;
            }
            break;
        case '$':
            Transaction >> FILENAME;
            Data_ouput.open(FILENAME);
            Data_ouput << *structure;
            break;
        default:
            cout << "\nError420 Operator not supported: " << op << endl;
            break;
        }
    }
    // Fin du programme
    return 0;
}

推荐答案

整个递归调用并没有像您期望的那样运行.输出的是从顶级 parcour() 调用返回的 return 值.由于内部递归调用似乎对返回值没有贡献,因此调用是发生还是跳过并不重要.

The whole recursive call is not working as you do expect it to run. What gets outout is the return value returned from your toplevel parcour() call. As the internal recursive calls seem not to contribute to the return value, it is not important whether the calls occur or would just be skipped.

要实现您所描述的意图,您需要将输出对象传递给 parcour() 并在该函数中执行您需要的任何输出.

To achieve what you described to intend you woud need to pass in the output object to parcour() and do the output of whatever you need within that function.

这篇关于在 ostream 函数中使用递归函数作为输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆