1
\$\begingroup\$

I made a generic tree class, which is meant to be useful for generating random sequences of elements, for example, sentences (sequences of strings).

Also, I have some concernings regarding the tree's code:

  • Is random_tree a suitable name for the class?
  • Is the variadic add_children method implemented correctly?

Code:

random_tree.hpp:

#ifndef CYNODELIC_MISCELLANEOUS_RANDOM_TREE_HPP
#define CYNODELIC_MISCELLANEOUS_RANDOM_TREE_HPP

#include <ostream>
#include <cstdlib>
#include <cstddef>
#include <vector>
#include <memory>
#include <random>

namespace cynodelic { namespace miscellaneous {

template <typename T>
class random_tree
{
    private:
        // Data
        T data_;

        // Children nodes
        std::vector<std::shared_ptr<random_tree<T>>> m_children;

        // Is this node a leaf?
        bool is_leaf;

        // If this node is root, is this one empty?
        bool is_root_empty;
    public:
        // Empty constructor
        random_tree() :
            is_leaf(true),
            is_root_empty(true) {}

        // Initialize with a single element of type T
        random_tree(const T& x) :
            is_leaf(true),
            is_root_empty(false),
            data_(x) {}

        // Copy constructor
        random_tree(const random_tree<T>& x) :
            data_(x.data_),
            m_children(x.m_children),
            is_leaf(x.is_leaf),
            is_root_empty(x.is_root_empty) {}

        // Copy assignment operator
        random_tree<T>& operator=(const random_tree<T>& x)
        {
            data_ = x.data_;
            m_children = x.m_children;
            is_leaf = x.is_leaf;
            is_root_empty = x.is_root_empty;

            return *this;
        }

        // Add elements (an element of type T or another tree)
        template <class Last>
        void add_children(const Last& x)
        {
            m_children.emplace_back(new random_tree<T>(x));
            is_leaf = false;
        }

        // Add multiple elements
        template <class First,class... Others>
        void add_children(const First& x,const Others& ... rest)
        {
            add_children(x);
            add_children(rest...);
        }

        // Get a child node
        random_tree<T> operator[](const std::size_t& idx) const
        {
            return *m_children[idx];
        }

        // Ammount of children nodes
        std::size_t size() const
        {
            return m_children.size();
        }

        // Node data
        T data() const
        {
            return data_;
        }

        // Pick randomly nodes and their children, then make a std::vector<T>
        // with them.
        // NOTE: Use a random number engine like the ones in the <random>
        // header.
        template <class RandomNumberEngine>
        std::vector<T> random_walk(RandomNumberEngine& rgen)
        {
            std::vector<T> out;

            if (!is_leaf)
            {
                std::uniform_int_distribution<std::size_t> dt(0,m_children.size()-1);

                // Random element index
                std::size_t a = dt(rgen);

                // Add an element
                out.push_back((*m_children[a]).data());

                // Keep adding elements until "arrive" to a leaf node
                std::vector<T> aux = (*m_children[a]).random_walk(rgen);

                // Append the nodes
                out.insert(out.end(),aux.begin(),aux.end());
            }

            return out;
        }

        // Print the tree structure
        void print_structure(std::ostream& os)
        {
            print_structure_impl(os,0);
        }
    private:
        void print_structure_impl(std::ostream& os,std::size_t level = 0)
        {
            if (!is_leaf)
            {
                // Ammount of children nodes
                std::size_t s = m_children.size();

                if (!is_root_empty)
                    level++;

                // Do the printing
                for (std::size_t i=0;i<s;i++)
                {                   
                    os << std::string(2*level,' ') << "+=+> " << (*m_children[i]).data() << '\n';
                    (*m_children[i]).print_structure_impl(os,level);
                }

                level--;
            }
        }
};

}} // end of "cynodelic::miscellaneous" namespace

#endif // CYNODELIC_MISCELLANEOUS_RANDOM_TREE_HPP

Example:

#include <iostream>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <vector>
#include <random>

#include "cynodelic/miscellaneous/random_tree.hpp"

// A short alias for random_tree<std::string>
using string_tree = cynodelic::miscellaneous::random_tree<std::string>;

int main(int argc,char **argv)
{
    std::random_device rd;
    std::mt19937 rnd(rd());

    string_tree snt_end("you");

    string_tree snt_end_A("nasty");
    snt_end_A.add_children(
        "piece of c**p.",
        "piece of s**t.",
        "pig.",
        "crybaby.",
        "coward."
    );

    string_tree snt_end_B("disgusting");
    snt_end_B.add_children(
        "piece of c**p.",
        "piece of s**t.",
        "pig.",
        "crybaby.",
        "coward."
    );

    string_tree snt_end_C("f****ng");
    snt_end_C.add_children(
        "piece of c**p.",
        "piece of s**t.",
        "pig.",
        "crybaby.",
        "coward."
    );

    string_tree snt_end_D("smelly");
    snt_end_D.add_children(
        "piece of c**p.",
        "piece of s**t.",
        "pig.",
        "crybaby.",
        "coward."
    );

    string_tree snt_end_E("brainless");
    snt_end_E.add_children(
        "piece of c**p.",
        "piece of s**t.",
        "pig.",
        "crybaby.",
        "coward."
    );

    snt_end.add_children(snt_end_A,snt_end_B,snt_end_C,snt_end_D,snt_end_E);

    // The tree
    string_tree snt;

    string_tree sntA("You will regret being born,");
    sntA.add_children(snt_end);

    string_tree sntB("Say your last words,");
    sntB.add_children(snt_end);

    string_tree sntC("It's really, really funny to see you crying,");
    sntC.add_children(snt_end);

    string_tree sntD("Let me to drink your delicious tears,");
    sntD.add_children(snt_end);

    string_tree sntE("What are you going to do now?");
    sntE.add_children(
        "Nothing?",
        "Cry?",
        "Tickle me?",
        "Cry a lot?",
        "Make memes of me?",
        "Throw flowers at me?"
    );

    snt.add_children(sntA,sntB,sntC,sntD,sntE);

    std::cout << "Tree structure:\n";
    snt.print_structure(std::cout);
    std::cout << '\n';

    // Generate 20 outputs
    std::cout << "Outputs:\n";
    for (std::size_t i=0;i<20;i++)
    {
        // Pick some elements from the tree
        std::vector<std::string> words = snt.random_walk(rnd);

        // Print the sentence
        std::cout << '>';
        for (const std::string& w : words)
            std::cout << ' ' << w;

        std::cout << '\n';
    }
}

Warning: Some bad language follows.

Output example:

Tree structure:
+=+> You will regret being born,
  +=+> you
    +=+> nasty
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> disgusting
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> f****ng
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> smelly
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> brainless
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
+=+> Say your last words,
  +=+> you
    +=+> nasty
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> disgusting
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> f****ng
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> smelly
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> brainless
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
+=+> It's really, really funny to see you crying,
  +=+> you
    +=+> nasty
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> disgusting
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> f****ng
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> smelly
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> brainless
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
+=+> Let me to drink your delicious tears,
  +=+> you
    +=+> nasty
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> disgusting
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> f****ng
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> smelly
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
    +=+> brainless
      +=+> piece of c**p.
      +=+> piece of s**t.
      +=+> pig.
      +=+> crybaby.
      +=+> coward.
+=+> What are you going to do now?
  +=+> Nothing?
  +=+> Cry?
  +=+> Tickle me?
  +=+> Cry a lot?
  +=+> Make memes of me?
  +=+> Throw flowers at me?

Outputs:
> What are you going to do now? Tickle me?
> What are you going to do now? Tickle me?
> Let me to drink your delicious tears, you smelly piece of s**t.
> It's really, really funny to see you crying, you disgusting piece of c**p.
> Let me to drink your delicious tears, you smelly crybaby.
> What are you going to do now? Tickle me?
> Let me to drink your delicious tears, you smelly crybaby.
> Say your last words, you smelly crybaby.
> You will regret being born, you smelly pig.
> Say your last words, you brainless pig.
> Say your last words, you f****ng crybaby.
> It's really, really funny to see you crying, you disgusting piece of c**p.
> What are you going to do now? Make memes of me?
> You will regret being born, you disgusting piece of s**t.
> It's really, really funny to see you crying, you disgusting piece of c**p.
> You will regret being born, you disgusting crybaby.
> You will regret being born, you f****ng piece of c**p.
> You will regret being born, you brainless coward.
> Let me to drink your delicious tears, you nasty pig.
> It's really, really funny to see you crying, you disgusting coward.

Suggestions, improvements, etc. are welcome.

\$\endgroup\$
  • 2
    \$\begingroup\$ Nothing against the question or the code itself. I downvoted because this is useless childish nonsense crying for attention. There are better, more constructive ways to do this. \$\endgroup\$ – Mathieu Guindon Mar 20 '17 at 15:24
  • 1
    \$\begingroup\$ I tend to agree with @Mat'sMug that, while the approach and code can be interesting, the foul/insulting output is rather uncalled for. \$\endgroup\$ – Phrancis Mar 20 '17 at 15:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.