The Artima Developer Community
Sponsored Link

Design Forum
C++ way to design tree structures

3 replies on 1 page. Most recent reply: Mar 4, 2009 10:20 AM by Jan Bessai

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 3 replies on 1 page
Jan Bessai

Posts: 8
Nickname: janbessai
Registered: Sep, 2008

C++ way to design tree structures Posted: Mar 3, 2009 5:59 PM
Reply to this message Reply
Advertisement
Hi,
after reading quite a lot of interviews with C++ gurus I am trying to improve my coding style and to abstain from pointers and manual heap allocation where ever I can.
Therefore I'm curios: What is the recommended way to design tree like structures in C++?
I experimented a lot with it, but I cannot think of a good way to implement it without pointers. All stl containers I thought about seem problematic.
Having vector, deque, list, etc. directly holding child nodes is inconvenient when there are sparse slots, like it occurs in binary search trees. Map, which would be perfect for that, only becomes efficient if there are many child nodes.
Is storing auto_ptr as attributes or in containers the appropriate solution? Is there any generic way to deal with data that should be deliberately uninitialized to leave open slots - despite null-pointers?
Thanks in advance,
Jan


Jan Bessai

Posts: 8
Nickname: janbessai
Registered: Sep, 2008

Re: C++ way to design tree structures Posted: Mar 4, 2009 4:32 AM
Reply to this message Reply
Update:
After some more investigation I found boost::optional to be the right thing.
I'll post an example later :)

Jan Bessai

Posts: 8
Nickname: janbessai
Registered: Sep, 2008

Re: C++ way to design tree structures Posted: Mar 4, 2009 5:48 AM
Reply to this message Reply

#ifndef TREE_HPP
#define TREE_HPP

#include <vector>
#include <boost/optional.hpp>

template <typename T, int max_children = 2>
class tree : public std::vector< boost::optional
< tree< T, max_children > > >
{
private:
boost::optional<T> data;
public:

tree() : std::vector< boost::optional
< tree< T, max_children > > >
(max_children), data()
{
}

tree(const T & some_data) : std::vector< boost::optional
< tree< T, max_children > > >
(max_children), data(some_data)
{
}

boost::optional<T> & operator*()
{
return data;
}

const boost::optional<T> & operator*() const
{
return data;
}
};

#endif

This approach is very simple but yet comfortable and quite generic to use. By making tree a subtype of vector it is possible to iterate over child notes like vector contents. Data-less tree nodes like those in b*-trees are also possible.
A fully stack based alternative (e.g. more suitable for binary trees) is also easy to think of - just remove inheritance, give tree a

optional<T> children []

member and access methods.


Here is an example of how to use my tree class:

#include <iostream>
#include <tree.hpp>

class bst
{
private:
tree<int> root;
void insert(tree<int> & pos, int x)
{
if (!(*pos))
*pos = x;
else
{
int child_num = (**pos > x ? 0 : 1);

if (!pos[child_num])
pos[child_num] = tree<int>(x);
else
insert(*pos[child_num], x);
}
}

void inorder_print(tree<int> & pos)
{
if (!!*pos)
{
if (!!pos[0]) inorder_print(*pos[0]);
std::cout << " " << **pos << " ";
if (!!pos[1]) inorder_print(*pos[1]);
}
}

public:
bst() : root()
{
}

void insert(int x)
{
insert(root, x);
}

void print()
{
inorder_print(root);
std::cout << std::endl;
}

};

using namespace std;

int main(int argc, char * argv[])
{
bst t;
t.insert(10);
t.insert(5);
t.insert(11);
t.insert(12);
t.insert(6);
t.print();
return 0;
}

Jan Bessai

Posts: 8
Nickname: janbessai
Registered: Sep, 2008

Re: C++ way to design tree structures Posted: Mar 4, 2009 10:20 AM
Reply to this message Reply

#ifndef TREE_HPP
#define TREE_HPP

#include <vector>
#include <boost/optional.hpp>

template <typename T, int child_count = 2, template <typename, typename> class parent_container_type = std::vector, template <typename> class Allocator = std::allocator >
class tree : public parent_container_type< boost::optional< tree <T, child_count, parent_container_type, Allocator> >, Allocator<boost::optional< tree <T, child_count, parent_container_type, Allocator> > > >
{
private:
boost::optional<T> data;
public:
typedef parent_container_type< boost::optional< tree <T, child_count, parent_container_type, Allocator> >, Allocator<boost::optional< tree <T, child_count, parent_container_type, Allocator> > > > parent_type;

tree() : parent_type(child_count), data()
{
}

tree(const T & some_data) : parent_type(child_count), data(some_data)
{
}

boost::optional<T> & operator*()
{
return data;
}

const boost::optional<T> & operator*() const
{
return data;
}
};

#endif


It is terrible to decipher the template arguments, but this way one can change the container class used for child nodes and its allocator on the fly.
Example above still works.
To have variadic templates would be great in this situation, as not all container classes imaginable need exactly two template parameters.

Flat View: This topic has 3 replies on 1 page
Topic: How design pattern can help if there are too many config items messy around Previous Topic   Next Topic Topic: OPEN SOURCE FROM JOOMLATAG

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use