Inheritance and AVL/BST Trees - c++

Is there any way to use the same insert function for both Bst and Avl tree? The problem is that Bst and Avl have different Node types, but I don't want to make the Bst Node a general case(with height and Node* parent inside, which makes no sense because there is no need of parent and height inside a Bst).
class Bst
{
public:
struct Node
{
int value;
Node* left;
Node* right;
};
Node* insert(Node* node) {/* do stuff using Bst::Node */}
// ...
};
class Avl : public Bst
{
public:
struct Node : public Bst::Node
{
int height;
Node* parent;
};
// now I want that Bst::insert use this Node
// instead of the old one
Node* insert(Node* node)
{
Node* inserted_node = Bst::insert(node);
/* rotations stuff */
return inserted_node;
}
};
Roughly what I'm trying to do is make Bst::Node "virtual".
So, how can I solve the problem of implenting the Avl Tree without rewriting the entire insert function just because Node changed?

Actually I'm also working on this stuff and I think you're very clear to describe what you want.
At the first, it's may be little confuse about the given interface, insert() should not return the pointer of the Node, doesn't it. We may use the findNode() function, which return the pointer of the Node and exactly do this work only.
Back to the main question, may be you can use the template to set your Node type for every function in the BST.
But the BST is not just a abstract interface, which also implement the BST operation, so it's not CRTP..
The pseudo code for now may be the following :
// pre-define :
//parent ptr also alleviate the implementation of BST.
template<typename T>
class BST{
... omit..
protected:
template<typename node_type>
class BST_Node{
public:
T val;
BST_Node *left, *right, *parent;
BST_Node():left{nullptr},
right{nullptr},
parent{nullptr}, val{}{};
// empty {} default to value initialization.
}
... omit ...
}
template<typename T>
class AVL_Node : public BST_Node{
public:
short height;
AVL_Node(T val):BST_Node(val), height(0){};
}
template<typename T>
void insert(T val){
AVL_Node<T> Node(val);
BST<T>::insert_node<AVL_Node>(Node);
AVL_Node<T>* ptr = BST<T>::find_node<AVL_Node>(val);
ptr->height = BST<T>::get_height(ptr);
state = chk_balance(ptr);
switch(state){
case 0: // tree very balance..
break;
case 1:
LL_rotate(ptr);
break;
case 2:
RR_rotate(ptr);
break;
... omit
}
}
# help this post solve your question..

Maybe you want CRTP (in which case you haven't given enough info about your needs for even a rough example, but a simpler less powerful template approach may make more sense to you. Have a base class (under each of your tree types) that has no data members, and just defines static template functions for the common code. Since the functions are static, you need to pass in the relevant data (for insert that should be &root) but that should not be much trouble. (Rough and untested):
struct tree_base
{
template <class Node>
static Node* insert( Node** where, Node* what)
{
Node* here;
while ( (here = *where) != 0 )
{
if ( *what < *here ) where = &(here->left);
else if ( *here < *what ) where = &(here->right);
else
{
Trying to insert something already there, what should be done
}
}
*where = what;
return what; // Is that the desired return?
}
};
Then each of your real tree classes would inherit from tree_base and would call tree_base::insert(&root, new_node) to do the common parts of insert
A CRTP version of that would allow root to be a member of the base class even though it points to the Node type of the derived class. Given root as a member of the base class, the insert function doesn't need to be static and doesn't need to take &root as input. And since a CRTP base class is already correctly templated to have access to the Node type, the base class insert method wouldn't need to be a template. All that would be a lot more things to learn (by looking at some real examples of CRTP) and probably overkill for the code sharing you want.

Related

How to structure the inheritance from generic tree to a-b tree

I am trying to implement an a-b tree, as a derived class from a generic tree.
The generic tree node is as follows:
template<typename T>
struct TreeNode
{
T value;
std::vector<TreeNode*> children;
//Some other trivial stuff
};
The structure of the a-b node is as follows:
template<typename T>
struct ABTreeNode : TreeNode<T>
{
std::vector<T> keys;
//The idea is to omit the T value field of the base node and use that vector for the keys
};
Also in the generic tree class there exists a root field
TreeNode *root;
And the a-b constructor is
template<Typename T>
ABTree<T>::ABTree(T value)
{
GenericTree<T>::root = new ABTreeNode;
root->keys.push_back(value);
}
Now, the way this is made, I need to use down casting in a lot of the a-b tree methods, for example:
template<typename T>
bool ABTree<T>::search(T value)
{
ABTreeNode *node = GenericTree<T>::root;
//....
}//Downcast base to derived
As far as I know down casting is a bad practice and indicates bad design. The fact that I use variables defined in the derived struct but declare the node as base struct seems very error prone. What would happen if that node was created as a base node and not derived?
Eg:
//Somewhere:
TreeNode *node = new TreeNode;//Instead of new ABTreeNode
//..
//Somewhere else
node->keys//Shouldn't that be an error?
Is my approach correct? If not how should I structure it better?
PS: spare the raw pointers please.
Sharing code by inheritance is a bad design. Better is to use Composition - see https://en.wikipedia.org/wiki/Composition_over_inheritance
To share code between different implementations of various trees I would extract common fields into a struct.
template <class T, class ChildT>
struct TreeNodeCommons
{
T nodeValue;
std::vector<ChildT*> children;
// more common fields
}
Then I would attach it to Nodes of different types.
template<typename T>
struct ABTreeNode
{
TreeNodeCommons<T, ABTreeNode<T>> commons;
std::vector<T> keys;
};
You may then write templated algorithms assuming Node contains field named commons and you may write Node specific algorithms as well. And there is no dynamic_casts.

Alternative to template variables?

I'm building a binary search tree. As the generic person I am, I want to allow all types to be able to act as keys to nodes in the tree.
So I came up with the following:
class foo
{
private:
template<class T>
struct node
{
T key;
node* left;
node* right;
};
node<>* _root; //point of interest
public:
//.....
template<class T>
void insert(const T& key);
};
As I insert the nodes into the tree, I can create node objects according to the type of the key, but I don't know how to declare the _root in such a way (when using insert on an empty tree, I can easily pick the type for _root).
I believe C++14's template variables can help me here, but unfortunately MSVC's compiler hasn't implemented that feature yet.
Question: How do I declate _root in the most generic way? How did people do it in the past?
Just storing nodes is not a problem:
class foo
{
struct node
{
virtual ~node() {}
node * left;
node * right;
}
template<typename T>
struct key_node: node
{
T key;
~value_node() {}
}
node *root;
};
The problem will come when you want to access the key value within a node (because you will need to store the type information somehow).
Alternately, you can use boost::any instead of a T template:
class foo
{
struct node
{
boost::any key;
node * left;
node * right;
}
node *root;
};
... and use the interface of boost::any to get the value of they key (but even here you will probably need information on the type stored in any before you can access it in a generic way).

Would making a binary search tree out of a struct over a class node be bad?

I'm not sure if i should.. or should not use a struct to create a binary search tree, the other option is to create the nodes out of a separate node class. with a data, left and right. Which one is better? And why?
heres my code for the BST
template <typename T>
class BST : public SearchableADT<T>
{
public:
BST(void){ head = NULL; numnodes = 0; }
virtual ~BST(void);
virtual int loadFromFile(string filename);
virtual void clear(void);
virtual void insertEntry(T info);
virtual void deleteEntry(T info);
virtual bool isThere(T info);
virtual int numEntries(void);
//needed for comparison to AVL
int BST<T>::height(t_node* tPTR);
protected:
struct t_node
{
string data;
t_node *L;
t_node *R;
};
int numnodes;
t_node* head;
t_node* cPTR; //current pointer
t_node* pPTR; //parent pointer
t_node* tPTR; //temporary pointer
}; // end of class BST
I'm not sure if you understand the difference between struct and class but basically:
struct
Has public access for all of its members by default and
class
Has private access for all of its members by default.
You can achieve the same thing with both of them but many programmers, including myself, tend to use structs for POD objects (Plain Old Data) for straight up access (It makes it easier to write less).
That said, I think you should put your Node class outside in a different file since the BST and Node classes are very different. Since you gave your BST class a template, I am assuming that you are gonna use more than just the Node class, which gives more reason to separate the files for the projects that you might not use the Node class. If you aren't going to use more than just a Node class, you might consider removing the template and defining the Node struct/class inside the BST class!
It is better to create two classes, one for the BST and another for the node. They are two different abstractions. A node is a simpler abstraction whose main purpose is to hold the data necessary to define a BST. A BST is a higher level abstraction. It's a collection class with its own constraints and expectations.

C++: Does this pattern have a name, and can it be improved?

The motivation
Let's say I'm writing a Tree class. I will represent nodes of the tree by a Tree::Node class. Methods of the class might return Tree::Node objects and take them as arguments, such as a method which gets the parent of a node: Node getParent(Node).
I'll also want a SpecialTree class. SpecialTree should extend the interface of a Tree and be usable anywhere a Tree is.
Behind the scenes, Tree and SpecialTree might have totally different implementations. For example, I might use a library's GraphA class to implement a Tree, so that Tree::Node is a thin wrapper or a typedef for a GraphA::Node. On the other hand, SpecialTree might be implemented in terms of a GraphB object, and a Tree::Node wraps a GraphB::Node.
I'll later have functions which deal with trees, like a depth-first search function. This function should accept both Tree and SpecialTree objects interchangeably.
The pattern
I will use a templated interface class to define the interface for a tree and a special tree. The template argument will be the implementation class. For example:
template <typename Implementation>
class TreeInterface
{
public:
typedef typename Implementation::Node Node;
virtual Node addNode() = 0;
virtual Node getParent(Node) = 0;
};
class TreeImplementation
{
GraphA graph;
public:
typedef GraphA::Node Node;
Node addNode() { return graph.addNode(); }
Node getParent() { // ...return the parent... }
};
class Tree : public TreeInterface<TreeImplementation>
{
TreeImplementation* impl;
public:
Tree() : impl(new TreeImplementation);
~Tree() { delete impl; }
virtual Node addNode() { return impl->addNode(); }
virtual Node getParent() { return impl->getParent(); }
};
I could then derive SpecialTreeInterface from TreeInterface:
template <typename Implementation>
class SpecialTreeInterface : public TreeInterface<Implementation>
{
virtual void specialTreeFunction() = 0;
};
And define SpecialTree and SpecialTreeImplementation analogously to Tree and TreeImplementation.
My depth-first search function might look like this:
template <typename T>
void depthFirstSearch(TreeInterface<T>& tree);
and since SpecialTree derives from TreeInterface, this will work for Tree objects and SpecialTree objects.
Alternatives
An alternative is to rely more heavily on templates so that SpecialTree isn't a descendent of TreeInterface in the type hierarchy at all. In this case, my DFS function will look like template <typename T> depthFirstSearch(T& tree). This also throws out the rigidly defined interface describing exactly what methods a Tree or its descendents should have. Since a SpecialTree should always act like a Tree, but provide some additional methods, I like the use of an interface.
Instead of the TreeInterface template parameter being the implementation, I could make it take a "representation" class that defines what a Node looks like (it will also have to define what an Arc looks like, and so on). But since I'll potentially need one of these for each of the implementations, I think I'd like to keep this together with the implementation class itself.
What do I gain by using this pattern? Mostly, a looser coupling. If I'd like to change the implementation behind Tree, SpecialTree doesn't mind at all because it only inherits the interface.
The questions
So, does this pattern have a name? I'm using the handle-body pattern by storing a pointer to ContourTreeImplementation in ContourTree. But what about the approach of having a template-ized interface? Does this have a name?
Is there a better way to do this? It does seem that I am repeating myself a lot, and writing a lot of boilerplate code, but those nested Node classes give me trouble. If Tree::Node and SpecialTree::Node had reasonably similar implementations, I could define a NodeInterface interface for a Node in TreeInterface, and override the implementation of the node class in Tree and SpecialTree. But as it is, I can't guarantee that this is true. Tree::Node may wrap a GraphA::Node, and SpecialTree::Node may wrap an integer. So this method won't quite work, but it seems like there might still be room for improvement. Any thoughts?
Looks like a mixture of the Curiously Recurring Template Pattern and the Pimpl idiom.
In the CRTP, we derive Tree from TreeInterface<Tree>; in your code you're deriving Tree from TreeInterface<TreeImplementation>. So it's also as #ElliottFrisch said: it's an application of the strategy pattern. Certain parts of the code care that Tree conforms to TreeInterface, while certain other parts care about the fact that it uses the particular strategy TreeImplementation.
Is there a better way to do this? It does seem that I am repeating myself a lot
Well, it depends what your runtime requirements are. When I look at your code, the thing that jumps out at me is that you're using virtual methods — slooooow! And your class hierarchy looks like this:
Tree is a child of
TreeInterface<TreeImplementation>
SpecialTree is a child of
TreeInterface<SpecialTreeImplementation>
Notice that the fact that TreeInterface<X>::addNode() happens to be virtual has absolutely no bearing on whether TreeInterface<Y>::addNode() is virtual! So making those methods virtual doesn't gain us any runtime polymorphism; I can't write a function that takes an arbitrary instance of TreeInterfaceBase, because we haven't got a single TreeInterfaceBase. All we've got is a bag of unrelated base classes TreeInterface<T>.
So, why do those virtual methods exist? Aha. You're using virtual to pass information from the derived class back up to the parent: the child can "see" its parent via inheritance, and the parent can "see" the child via virtual. This is the problem that is usually solved via CRTP.
So, if we used CRTP (and thus didn't need the virtual stuff anymore), we'd have just this:
template <typename Parent>
struct TreeInterface {
using Node = typename Parent::Node;
Node addNode() { return static_cast<Parent*>(this)->addNode(); }
Node getParent(Node n) const { return static_cast<Parent*>(this)->getParent(n); }
};
struct ATree : public TreeInterface<ATree> {
GraphA graph;
typedef GraphA::Node Node;
Node addNode() { return graph.addNode(); }
Node getParent(Node n) const { // ...return the parent... }
};
struct BTree : public TreeInterface<BTree> {
GraphB graph;
typedef GraphB::Node Node;
Node addNode() { return graph.addNode(); }
Node getParent(Node n) const { // ...return the parent... }
};
template <typename Implementation>
void depthFirstSearch(TreeInterface<Implementation>& tree);
At this point someone would probably remark that we don't need the ugly pointer-casting CRTP at all and we could just write
struct ATree {
GraphA graph;
typedef GraphA::Node Node;
Node addNode() { return graph.addNode(); }
Node getParent(Node n) const { // ...return the parent... }
};
struct BTree {
GraphB graph;
typedef GraphB::Node Node;
Node addNode() { return graph.addNode(); }
Node getParent(Node n) const { // ...return the parent... }
};
template <typename Tree>
void depthFirstSearch(Tree& tree);
and personally I would agree with them.
Okay, you're concerned that then there's no way of ensuring through the typesystem that the T the caller passes to depthFirstSearch actually conforms to TreeInterface. Well, I think the most C++11-ish way of enforcing that restriction would be with static_assert. For example:
template<typename Tree>
constexpr bool conforms_to_TreeInterface() {
using Node = typename Tree::Node; // we'd better have a Node typedef
static_assert(std::is_same<decltype(std::declval<Tree>().addNode()), Node>::value, "addNode() has the wrong type");
static_assert(std::is_same<decltype(std::declval<Tree>().getParent(std::declval<Node>())), Node>::value, "getParent() has the wrong type");
return true;
}
template <typename T>
void depthFirstSearch(T& tree)
{
static_assert(conforms_to_TreeInterface<T>(), "T must conform to our defined TreeInterface");
...
}
Notice that my conforms_to_TreeInterface<T>() will actually static-assert-fail if T doesn't conform; it will never actually return false. You could equally well make it return true or false and then hit the static_assert in depthFirstSearch().
Anyway, that's how I'd approach the problem. Notice that my entire post was motivated by the desire to get rid of those inefficient and confusing virtuals — someone else might latch onto a different aspect of the problem and give a totally different answer.

is my code uses OOPS concept in correct way or am i making it unnecessary complicated?

I have seen lots of codes to implement BST(online and in some books).Most of those code have a struct like below:-
struct node{
int data;
struct node *left;
struct node *right;
};
class tree{
private:
node *root;
public:
//other helper function like insert,delete,display
};
But if i want to use OOPS in much better way then would it be correct to say that i should create class node{}; instead of using struct ???
I have written code below , which according to me is uses OOPS concept in much better way.
please suggest me any changes if you find and problem with the design:-
my code :-
#include<iostream>
using namespace std;
class node{
private:
int data;
node *left;
node *right;
public:
node()
{
data=0;
left=NULL;
right=NULL;
}
node(int val)
{
data=val;
left=NULL;
right=NULL;
}
int getData()
{
return data;
}
node* getLeft()
{
return left;
}
node* getRight()
{
return right;
}
void setData(int val)
{
data=val;
}
void setLeft(node *l)
{
left=l;
}
void setRight(node *r)
{
right=r;
}
};
class tree{
private:
node *root;
node *insertHelper(node*,int);
void inorderHelper(node*);
public:
tree()
{
root=NULL;
}
void insert(int val)
{
if(root==NULL)
{
root=new node(val);
return;
}
insertHelper(root,val);
}
void inorder();
};
node *tree::insertHelper(node *root,int val)
{
if(root==NULL)
{
root=new node(val);
return root;
}
else
{
if(root->getData() > val)
{
root->setLeft(insertHelper(root->getLeft(),val));
}
else
{
root->setRight(insertHelper(root->getRight(),val));
}
}
}
void tree::inorder()
{
if(root)
{
inorderHelper(root);
}
}
void tree::inorderHelper(node *temp)
{
if(temp!=NULL)
{
inorderHelper(temp->getLeft());
cout<<temp->getData()<<" ";
inorderHelper(temp->getRight());
}
}
By creating class node{} and keeping left ,right,data as private member , am i doing too much and making things complicated or it is a good approach???
BSTs, while in some ways very complicated, are really very simple. What you're doing - setting everything private unless it absolutely needs to be otherwise - is good OOP convention, but isn't really necessary here. You have a single class - that means inheritance and polymorphism are irrelevant - which is used for basically a single, very straightforward purpose, which means that restricting access doesn't really do much (it's very improbable that your code will be used by someone else who decides to arbitrarily mess with fields that shouldn't be messed with).
You aren't losing any functionality by making your struct a class, but you aren't really gaining any, either. If, later on, you have even the hint of a plan to somehow use a modified BST of some sort, by all means use classes, because then inheritance will become relevant; but if not, there isn't much of a difference between class and struct, other than style.
Generally speaking, if the construct you are going to make is only holding data (and does not need to change or access the data directly), then you do not need a class. This is why, with a BST, a struct will suffice for the node when there is already a Tree class.
Why would a struct for the node suffice, though? Well, that comes down to the fact that you don't need to have the methods that you have provided in your "node" class for two reasons. Firstly, anything that the methods you have in your node class are accomplishing is somewhat unnecessary; the Tree class is already responsible for traversing the BST, adding new nodes, deleting unwanted nodes, and obtaining data (you typically do not want to have mutator functions that will change the values stored in the nodes after they have been added as this could result in a BST that does not adhere to the structure required for a BST). Secondly, as stated above, the node only needs to hold data. This introduces an important paradigm in C++ which is one of the key differences that sets it apart from other languages that have objects: it allows us to only make classes when they are absolutely necessary (in Java, for example, everything is a class!). Accordingly, we should take advantage of this and use structs when a class is not required. In my experience, having fewer classes will result in code that is easier to write and for others to understand.
Regarding making the member variables of the node struct private in the class you have defined: This is a good idea for data encapsulation and can prevent mishaps, but just try to be careful when you are programming the BST and you should be okay!
Hope this helps and good luck programming :)