Design and implementation of a 2-3 tree with polymorphism - c++

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.

Related

C++ n-arry tree with different elements

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.

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.

Method is being called on class with uninitialized attributes despite constructors

Premise: suppose I have a rectangular subset of 2D space and a collection of points, all with different x-values, in this subset. In the interest of the optimization of an algorithm as yet unwritten, I want to split my box into cells according to the following process: I halve my rectangle into 2 equal parts along the x-axis. Then I repeatedly halve each sub-rectangle until every cell contains either 1 point or none at all.
In this illustration the vertical lines represent the “halving process” and the lines are ordered by darkness (darker is newer).
First I’ll define two basic classes:
class Point{
private:
double x;
double y;
public:
// [...]
// the relevant constructor and getter
// overloaded operators +, -, * for vector calculations
};
class Box{
private:
Point bottom_left_point;
double width;
double height;
public:
Box(Point my_point, double my_x, double my_y) : // constructor
bottom_left_point(my_point), width(my_x), height(my_y){}
bool contains(const Point& p); // returns true iff the box contains p in the geometric sense
Box halve(bool b) const; // takes a boolean as input and returns the left half-rectangle for false, and the right half-rectangle for true
};
Now to implement the “halving algorithm” I’ll need a binary tree-like structure. Each node will represent a sub-cell of the rectangle (with the root node representing the total rectangle). A node may have two children, in which case the children represent its left and right halves. A node may also have a pointer to a particle which exists in the cell. The ultimate idea will be to start with an empty tree and insert the points in, one by one using a method insert(Point* to_be_inserted).
So I’ll define the following recursive class, whose private attributes are rather self-explanatory:
class Node;
class Node{
private:
enum node_type{ INT, EXT, EMPTY };
node_type type;
// type == INT means that it is an interior node, i.e. has children
// type == EXT means that it is an exterior node, i.e. has no children but contains a point
// type == EMPTY means that it has no children and no point
std::array<Node*,2> children;
Box domain; // the geometric region which is being represented
Point* tenant; // address of the particle that exists in this cell (if one such exists)
public:
Node(Box my_domain) :
type(EMPTY), children({nullptr}), domain(my_domain){}
//
// to be continued...
The first order of business is to define a subdivide() method which endows my node with two children:
void Node::subdivide(void){
type = INT;
children[0] = new Node(domain.halve(false));
children[1] = new Node(domain.halve(true));
}
Now everything is in place to write the crux of this whole affair, the insert method. Since it will be written recursively, the easiest solution is to have a boolean return type which tells us if the insertion was a success or failure. With this in mind, here’s the code:
bool Node::insert(Point* to_be_inserted){
if(not domain.contains(*to_be_inserted)) return false;
switch(type){
case INT:{
for(Node* child : children) if(child->insert(to_be_inserted)) return true;
return false;
}
case EXT:{
subdivide();
for(Node* child : children) if(child->insert(to_be_inserted)) break;
tenant = nullptr;
for(Node* child : children) if(child->insert(to_be_inserted)) return true;
break;
}
case EMPTY:{
type = EXT;
tenant = to_be_inserted;
return true;
}
}
throw 1; // this line should not, in, theory ever be reached
}
(Note that, for the sake of abstraction and generality, I have used for loops on the array children when I could have simply written out the two cases.)
Explanation:
First we check if to_be_inserted is in the geometric region represented by this. If not, return false.
If this is an internal node, we pass the point on to the each child until it is successfully inserted.
If this is an external node, that means that we have to split the node in two in order to be able to properly isolate to_be_inserted from the point that currently lives in the node.
First we call multiply().
Then we attempt to insert the current tenant into one of the children (please excuse how obscene this sounds, I assure you that it’s unintentional).
Once that is done, we do the same with to_be_inserted and return the result. (Note that a priori the insertion would be a success at this point because of the preliminary call to box::contains.
Finally, if this is an EMPTY node, we simply have to assign tenant to *to_be_inserted and change type to EXT and we’re done.
Ok, so let's try it out with a simple main:
int main(void){
Box my_box(ORIGIN, 1.0, 1.0); // rectangle of vertices (0,0),(0,1),(1,0),(1,1)
Node tree(box); // initializes an empty tree representing the region of my_box
Point p(0.1, 0.1);
Point q(0.6, 0.7);
tree.insert(&p);
tree.insert(&q);
return 0;
}
This compiles, but upon running the exception at the bottom of insert is thrown after a few calls. How is this possible, given that at no point a Node is constructed without a type value?
Edit: I have noticed, as well as this one, several possible errors which may also occur with small changes in the code:
An inexplicable call to nullptr->insert(something)
A call to insert by the address 0x0000000000000018 which doesn't point to an initialized Node.
The entirety of the code, including a makefile with the relevant debugging flags, can be found at https://github.com/raphael-vock/phantom-call.

How to correctly allocate memory for same type of objects

i have this class, its alot like node when creating linked list.
class Element {
public:
int id;
int value;
bool parent;
bool is_ministry;
int children_count;
int children_in;
Element **children; //CHILDREN ARRAY
Element* next; //TO NOT LOSE ELEMENTS
Element(int _id,int _value,int _children_count=0,bool _is_ministry=false){
this->id=_id;
this->value=_value;
this->is_ministry=_is_ministry;
this->children_in=0;
if(_children_count>0)
this->parent=true;
else this->parent=false;
this->children_count=_children_count;
this->next=NULL;
if(_children_count>0){
this->children = new Element*[_children_count];
}
else this->children=NULL;
}
~Element(){
///delete children;
}
};
And i need this object to have an array of pointers to same type of objects, array size varies on the given input - children_count.
Can it be statically created? Values are read from file. I have chosen dynamic approach, but im not sure if its done correctly, because it works, but after i add 3 objects, the whole thing burns down. So im looking for plausible faults.
I am making something like a tree. Where one element has direct access to one level down same type of objects.
EDIT: MORE CODE
void chain_together(Element *_parent, Element *_child){
///CHILDREN_IN is and int which shows currently how much elements are in the array.
if(_parent->children_in>0){
for(int i=0;i<_parent->children_in;i++) ///CHEKING IF THERE ALREADY IS A LINK BETWEEN THEM
if(_parent->children[i]->id != _child->id){
_parent->children[_parent->children_in] = _child;
_parent->children_in++;
}
}else{
_parent->children[_parent->children_in] = _child;
_parent->children_in++;
}
}
Let's take a walk through the chain_together method.
if(_parent->children_in>0){
If the child list is not empty
for(int i=0;i<_parent->children_in;i++)
Visit at all known children
if(_parent->children[i]->id != _child->id){
If this child isn't the child we wish to add, add the child
_parent->children[_parent->children_in] = _child;
_parent->children_in++;
}
}else{
No children. Add the first child
_parent->children[_parent->children_in] = _child;
_parent->children_in++;
}
Walking through the addition of a few children to see what happens...
On the first child
just add them.
On the second child,
they are not the first child
add them
On the third child,
they are not the first child
add them.
they are not the second child
add them.
See the problem? If not...
On the fourth child,
they are not the first child
add them.
they are not the second child
add them.
they are not the third child
add them.
they are not the third child
add them.
This bug would have been trivial to detect by stepping through the code with a debugger. A debugger comes with ever compiler tool kit that's worth using. It is possibly the most important tool you will ever learn to use as a programmer.
Solution:
Test that the added child doesn't match all of the pre-existing children before adding the new child.

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