At https://github.com/erikerlandson/st_tree you will find a good template for creating trees for instance you can write:
tree<string, ordered<> > t;
t.insert("A");
// Insert strings at ply 1
node_iterator c = t.root().insert("C");
t.root().insert("B");
t.root().insert("D");
// Insert strings at ply 2
c->insert("F");
c->insert("E");
You can choose between ordered (using multiset), raw (using vector) and keyed node (using map), each node holds some data which also is the key for ordered and keyed node. It is not possible to make a tree with mixed type of nodes. I want to make an alternative template where the nodes not always have data but merely is a holder for some childs and also allows some mix. A simplified example could be:
tree t;
t.iterator it=t.insert(new node<raw_no_data<>>);
t.iterator it2=it->insert(new node<ordered_no_data<string>>); //indicating that its childs
//data should be string;
t.iterator it3=it->insert(new node<keyed_no_data<string>>);
it2->insert(new node<leave,string>(“B”));
it3->insert(new node<leave_key,string,int>(“D”,5));
node_base &n1=t[0].find(“B”); //looking in multiset
node_base &n2=t[1].find(“D”); //looking in map
In other words in a more general case, I want the option to access a node like this:
mynode=t[2][0]["cat"][1];
Where tree is a mix of ordered and raw nodes, and where we have no _data for childs of the raw node.
Does something like this already exist as open source? If not I will try to make such a project and upload it on GitHub.
Related
I want to build a n-arry tree from a document. For that i have 3 different types of elements for the tree:
Struct Nodes
Have a name
can contain other Nodes
Depth
Element Node (Leaf of the tree)
Have a Key
Have a value
Depth
Element Template Node (Leaf of the tree)
Have a placeholder which should be resolved later in the program
Depth
At the moment i think about something like this:
class Node {
public:
Node(int depth);
int depth() const;
private:
int depth_;
};
class StructNode : public Node {
...
private:
std::vector<std::unique_ptr<Node>> children;
};
class ElementNode : public Node {
...
};
class ElementTemplateNode : public Node {
...
};
The Tree will be generated from an File on Startup and reused to create an output string like this:
Structname:
key = value
key = value
Structname:
key = value
Structname:
key = value
...
Where the Key and value where directly read from the ElementNode or read from another file with the value of the placeholder inside the ElementTemplateNode
Is there maybe a better Structure for the Tree? Because with the current one i have to check first if its a StructNode, ElementNode or ElementTemplateNode
This is a typical structure for implementing a tree with different kind of nodes. Another variant would be the composite pattern.
The problem that you describe, is usually caused by asking the nodes about what they know, instead of telling them what to do. If you'd do it the other way round (tell, don't ask), you could get rid of those checks and benefit from polymorphism.
The different kind of nodes inherit from Node. You could design your tree using a uniform interface, with virtual functions defined for Node which then can be overridden for the different types of nodes. Calling the method would then do the right things, without need for a manual type check. For generating the output string, you'd tell the root node to generate a string. If it's a structure, it would add the heading and tell its children to generate a string, but if it's a leaf it would just add the key/value pair to the string. No need from outside to know anything about each node.
If the operation of exploring the tree shall not be implemented by the tree itself, the usual approach is to use a visitor pattern. The big advantage is that you write the vistor once, and it's then easy to specialize a new kind of visitor for different algorithms. Again, no need to check the type of the nodes. The pattern makes sure that the right elementary function is called for the right type of node.
I have to implement a 2-3 tree using a base class of a node and derived class of leaf and an innernode (i.e both "are-a" node).
But I don't understand how to start with the insertion in simple cases. Since we call the methods of node to insert, how is it supposed to know if what we insert needs to be an innernode or a leaf? And how does a node supposed to change itself to a leaf or an innernode?
Any tips/ideas on how to approach this?
Here's the structure, I didn't get very far though.
typedef int TreeKey;
class node {
public:
virtual ~node() {}
virtual void insert(TreeKey k, string d);
virtual void deletenode(TreeKey k);
virtual void findnode();
virtual node * findnode(TreeKey key);
protected:
struct info {
TreeKey key;
string data;
};
node* parent=nullptr;
};
class leaf : node {
info i;
public:
virtual void insert(TreeKey k, string d);
};
class innerNode : node {
vector<info> inf;
vector<node*> vect;
public:
virtual void insert(TreeKey k, string d);
};
Note: in this 2-3 tree, the data sits only in the leaves.
One way of doing things is as follows. There are others.
Have 4 separate classes: a 2-leaf-node, a 3-leaf-node, a 2-internal-node and a 3-internal-node. This solution gets rid of vectors and so minimises dynamic allocations.
One inserts an element, not a node. Each node knows what to do with inserted element. An internal node passes the element to one of the child nodes. A leaf node absorbs the element.
A 2-node absorbs an element by becoming a 3-node. A 3-node absorbs an element by becoming two 2-nodes, and passing an element back to its parent to absorb. The parent then itself changes and may pass an element up. This continues until some 2-node changes to a 3-node (its parent doesn't need to change, only replace its child pointer), or an element propagates all the way back to the root, and a new root is created.
How a node "becomes" something else? It cannot. Instead, it creates the new thing(s) it should become, copies its information to the new thing(s), returns the newly created thing(s) to the caller, and deletes itself. The caller then either replaces its old child with the newly created one, or itself "becomes" something else.
The insert method signature of the node could look like this:
typedef enum {none, expand23, split322} action;
action Node::insert(info& element, Node*& newNode1, Node*& newNode2);
If the node was a 2-node and it became a 3-node, the method creates a new 3-node and passes it back in newNode1. The parent has to replace the corresponding child pointer upon seeing expand23. The parent itself doesn't expand or split, so its insert returns none.
If the node was a 3-node and it splits, the method creates two new 2-nodes and passes them back in newNode1 and newNode2. It also passes back an element for that the parent to absorb. The parent will do either expand23 or split322 depending on what type it is.
If the root returns split322, a new root is created
"in this 2-3 tree, the data sits only in the leaves" — just noticed this remark. I'm not sure how this could ever work. A 2-3 tree has either 1 or 2 data items in each node, not just leaves. It cannot work otherwise. So I pretty much ignore this remark.
If you don't want to have separate classes for 2- and 3-nodes, then you don't need expand23 because a 2-node can turn into a 3-node without having to delete itself. split322 remains the same. I would not use vectors in this case. Since leaf nodes only store copies of keys that exist elsewhere, they can be stored as 3 (smart) pointers to keys (not an array, just 3 separate variables). You distinguish between a 2-node and a 3-node by looking at the third pointer. If it's a nullptr, this is a 2-node. Same thing about data in the leaves, store it in 3 separate pointers.
I'm trying to create a text-based adventure game. I'm thinking I want the map to be represented by different nodes where each node corresponds to a distinct location and has node pointer variables (left, forward, and right) that should point to another node in the respective direction. I tried to implement it as a linked list, but with this data structure, I could only have each node point to one other node. I want each node to point to three other nodes. Which data structure could I use to implement this or is this even possible?
A linked datastructure would do a good job of doing what you want:
example:
class location
{
std::string loc_name;
std::vector<std::pair<std::string,location*>> connections;
std::string description;
public:
bool add_link(location* loc, std::string dicription_to, std::string dicription_from);
//other parameters + functions to manage class
}
This would allow you to create locations such as:
location* loc = new location("graveyard");
loc->description = "A spooky graveyard on a hill, a cool mist floats amongst the gravestones and monuments";
loc->add_link(crypt /*previously defined*/,
"An imposing mausoleum with an open door, steps inside lead down into darkness",
"Moonlight filters down from the top of some steps, a way out?");
loc.add_link(spooky_house /*previously defined*/,
"The North gate of the graveyard",
"The entrance to the house's spooky graveyard");
I'd reccommend creating a map file you could read in though. Possibly using a template like this:
locations file:
/*locations, format = "name; description"*/
Spooky House; house_description
Crypt; crypt_description
Graveyard; A spooky graveyard on a hill, a cool mist floats amongst the gravestones and monuments
links file:
/*links, format = "index # (from); index # (to); description (from->to); description (to->from)"*/
3;2;An imposing mausoleum with an open door, steps inside lead down into darkness; Moonlight filters down from the top of some steps, a way out?
3;1;The North gate of the graveyard;The entrance to the house's spooky graveyard;
Loading the map would be as simple as reading in all the locations and pushing them into a vector for storage, then adding the links in to connect them.
You could implement a custom linked datastructure with linked positions on the map like this:
struct Map_Node{
Map_Node *left;
Map_Node *right;
Map_Node *forward;
/* other needed field*/
};
Then, you need to do the memory management on your own. For example by using smart pointers.
std::shared_ptr<Map_Node> entry{ new MapNode };
std::shared_ptr<Map_Node> hallway{ new MapNode };
entry->forward = &*hallway;
//and so on
An easier but less efficient for getting the next file would be a std::map. If each position
has its unique ID, e.g. a string, you could store the IDs of the neighboring fields and move freely on the map by using the ID.
struct Map_Node{
std::string name;
std::string left;
std::string right;
std::string forward;
/* other needed field*/
};
std::map<std::string, Map_Node> map;
Map_Node entry;
entry.name = "entry";
map[entry.name] = entry;
Map_Node hallway;
hallway.name = "hallway";
map[hallway.name] = hallway;
//links between:
map["entry"].forward = "hallway";
I want to store object that are given a certain name.
I wanted to use struct and then store them in a vector, but it was suggested to me that I should rather use a different data structure, a little more simple, but I cant seem to find one.
My current ("complex") solution:
//in header file
struct objStorage{
Classname obj;
string name;
};
vector<objStorage> vec;
//in constructor
objStorage firstObj;
firstObj.obj = new Classname();
firstObj.name = "foo";
vec.push_back(firstObj);
Is there a more simple solution (Data structure)?
I should add that I don't need the structure once I stored (copied?) it in the vector, because this is all happening in another class (constructor) so I don't want any problems when calling the constructor multiple times.
If you want to lookup items by some key, for example a string, the classic thing to use is a map:
std::map<std::string, Classname> items;
std::pair<std::map<std::string, Classname>::iterator, bool> inserted =
items.insert(std::make_pair(std::string("foo"), Classname()));
items["bar"] = Classname();
In this set up, if you really think you want to use pointers, you should consider some form of smart pointer.
There are other options, for example, C++11 introduces other lookup structures - e.g. unordered maps.
I have a node(basically the graph vertex) templated class like this:
template<class T>
class Node
{
public:
T Data;
Node<T>* Parent;
vector<Node<T>*> Children;
};
and then I have a templated graph class that encapsulates the root of the graph and I have a method the is supposed to generate an Eulerian Path(after it has checked if the conditions for the existence of an Eulerian Path are satisfied):
template<class T>
class Graph
{
public:
Node<T>* Root;
vector<Node<T>*> GetEulerianPath() const;
bool HasEulerianPath() const;
};
HasEulerianPath() just traverses the node(*vertex*) hierarchy and counts the amount of vertices that have an odd degree.If they are no more than two, it returns true.
Now the problem is - I'm not exactly quite sure how do implement the algorithm.Any tips?Should I just extract the entire hierarchy in a vector and iterate trough that or do I use some recursive method of Node?The Wikipedia Page suggest using a linked list...or maybe I should just generate an new smaller singledirectional Graph as an output for the GetEulerianPath() method?I'm confused at how to proceed here.
The way you have structured your Node class basically forms a doubly-linked list that is contained in a vector. There are a few issues (mathematically) that you appear to have:
A given "child" can have more than 1 "parent". In fact, if there are 2 "child" nodes, there would have to be 2 "parent" nodes in order for this to be an Eulerian cycle. You may want to redefine Node as follows:
template<class T>
class Node
{
public:
T Data;
list<shared_ptr<Node<T>>> Connections;
};
Which will allow you to change your Graph to:
template<class T>
class Graph
{
public:
shared_ptr<Node<T>> Start; // name change just to convey that there isn't a "root" node in an Eulerian cycle
list<shared_ptr<Node<T>>> GetEulerianPath() const;
bool HasEulerianPath() const;
};
This way, implementing Hierholzer's Algorithm is simply a matter of traversing the Connections for each node.
You need to convert your graph first. But definitely not to a std::vector.
For each node you need to be able to quickly get an unused edge (put them all in a linked list and remove when used).
Therefor each node should have a linked list of children not a std::vector.
Next, you need to be able to find nodes which have unused edges, you can just collect those in a linked list while traversing. You also need to build a linked list with your path while traversing, the list of unused edges should refer to this list so you can change the path in O(1).
(The Node<T>* Parent; in your code seems odd for a general graph.)