C++ n-arry tree with different elements - c++

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.

Related

Create special binary search tree using C++

I want to create a Binary search tree which has special Nodes. There should be three classes of Nodes, Internal Node, External Node and Root node, each inheriting a common parent Node and each type of node will have some unique function. Is it possible to create such a BST. The problem I am facing is suppose the first node I insert into the tree becomes the root node. The next node I insert will become External Node. Now if I insert another node then the external node has to become a internal node and the new node will become the external node. Also I cannot find a way to navigate through the tree from one node to another as the nodes will be of different types. Can a tree of this type be created. If yes then give me some suggestions of how this can be done.
If I understand correctly, you're worried about how objects in one class - External - need to become objects of another class - Internal. This, when C++ is a statically-typed language: Types (including the classes of objects) are determined at compile-time. Right?
Well, you can achieve this in at least one of two ways:
When an External node becomes Internal, delete the External node and replace it with an Internal node, properly initialized (e.g. to point at the new External node).
Give up on External and Internal being discrete types, and just check for children and parents to determine the node type dynamically.
Some more relevant reading material on these matters:
(Programming language) type systems in this Wikipedia page.
This SO question: What is duck typing?
The Circle-vs-Eclipse problem, and specifically the desire to stretch circles into ellipses.
You could use basic inheritance some type enum and recursive calls.
This could be a starting point:
enum NodeType
{
eRoot,
eInternal,
eExternal
};
class BinaryNode
{
public:
virtual NodeType GetType() = 0;
virtual void UpdateTree() = 0;
protected:
BinaryNode* ChildLeft;
BinaryNode* ChildRight;
BinaryNode* Parent;
};
class ExternalNode : public BinaryNode
{
NodeType GetType() override { return eExternal; }
void UpdateTree() override
{
//... Replace node instances here(e.g. delete this node and construct the correct new one given this sub tree. call new InternalNode(this) for example)
// Call this towards the parent node so the tree will be transformed accordingly
}
}
class InternalNode : public BinaryNode
{
NodeType GetType() override { return eInternal; }
void UpdateTree() override { //... }
}
class RootNode : public BinaryNode
{
NodeType GetType() override { return eRoot; }
void UpdateTree() override { //... }
}
This is just to give you an idea where to start. You can check the node type at runtime via GetType() and do some checks based on that.
Be aware that this kind of transformation is not particularly fast.
If you want this to be fast, don't use different types and virtual function calls and pointers.
Place your binary tree inside an array and use binary indexing, so at a given index "n" use 2*n+1 to get the left child and 2*n+2 to get the right child. Then use some flags (root, external, internal etc.) to determine which functions you want to call on the binary node. I wouldn't use inheritance like in my code example to be fast or more readable. In fact, deciding externally what functions to call on a node can be much more readable and less error-prone.

Can I group attributes of one class into one map?

If I have class "node", and wish to include all possible (say int) attributes. Is grouping them into one map good solution.
So instead:
class node{
int color;
int isVisited;
int weight;
public:
};
To have
class node{
map<string, int> property;
public:
setProperty(string property_label, int property_value)
{property[propery_label] = property_value;};
};
int main(){
node n;
n.setProperty("color",int(color::red));
n.setProperty("isVisited", 1);
n.setProperty("weight", 12);
}
EDIT:
The reason to do this is that, when transforming a graph, some local properties (like is visited during some traversal, or is it marked) are needed somewhere in the middle of an algorithm, but these local properties do not represent intrinsic property of a node, and are not needed in the output. Also, sometimes I need more than one "isVisited" variables.
One more reason is to keep the class "node" universal and open for new attributes that eventually might be needed.
The example you gave gives the impression that any node would have all the properties you provided (colour, isVisited, weight). If so it is (usually) better to keep the original class you started with.
There might be a few scenarios in which a map (or possibly rather std::unordered_map) might be superior, though; just a few examples:
You have a large number of possible (but pre-defined) attributes and each node only needs a rather small subset of. Possibly an enum is better suited as key then.
You want/need to store arbitrary attributes unknown at compile time.
Each node has the same attributes, but you mainly access them via user input; then especially an unordered_map could be faster than a (possibly long) if-else-chain.
In the end, all depends on the use case...
For strings as keys possibly a trie might be an interesting alternative, too.
A class (identical to a struct except it defaults to private access rather than public) is primarily to group elements of data and/or functionality together.
You node seems to simply group together three elements. So you probably want to start off with something as simple as:
struct node // access is public by default
{
int color;
int isVisited; // maybe a bool rather than int?
int weight;
}
...
node myNode;
myNode.color = ...
...
std::cout << myNode.weight;

I want to make a better tree than st_tree

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.

Design and implementation of a 2-3 tree with polymorphism

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.

Implementing Hierholzer's algorithm for a general-purpose graph in C++

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.)