Last active
August 29, 2017 15:21
-
-
Save DBJDBJ/b8920ffc1da2655c350ca113e6f647e5 to your computer and use it in GitHub Desktop.
Binary Tree made more useful, the easy and quick way thanks to modern C++ (c) 2017 by [email protected]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// IDE ONE link: https://ideone.com/X30oXu | |
#pragma once | |
#include <iostream> | |
using std::wostream; | |
namespace dbj { | |
namespace tree { | |
using namespace std; | |
/* | |
Binary Tree made more useful, the easy and quick way thanks to modern C++ | |
(c) 2017 by [email protected] | |
*/ | |
/* | |
each type T stored in a node has to have its releasing function | |
this will obviously be a policy pattern | |
*/ | |
template<typename T> void data_destroyer(T data) { data.~T(); } | |
/* | |
T is data type stored | |
*/ | |
template<typename T> | |
struct Node { | |
T data; | |
struct Node *left; | |
struct Node *right; | |
Node() { | |
this->data = T{} ; | |
this->left = this->right = nullptr; | |
} | |
typedef std::unique_ptr<Node<T>> NodeP; | |
NodeP smart () { | |
return std::make_unique<Node<T>>( | |
reinterpret_cast<Node<T> &>(*this) | |
); | |
} | |
/* | |
reminder: delete will call Node destructor | |
*/ | |
~Node() { | |
if (this->data) | |
data_destroyer(this->data); | |
if (this->left) | |
delete this->left; | |
if (this->right) | |
delete this->right; | |
} | |
/* | |
type T requires well behaved swap | |
*/ | |
static Node * root_creator( T data ) { | |
Node * root = new Node(); | |
std::swap(root->data, data); | |
return root; | |
} | |
/* | |
node insertion method creates balanced tree by default | |
it uses operator '<=' on the data type used and stored | |
it also uses Node<T>::root_creator() to create the node | |
*/ | |
static Node * insert(Node * root, const T & data) { | |
if (root == nullptr) { | |
root = root_creator(data); | |
} | |
else if (data <= root->data) | |
root->left = insert(root->left, data); | |
else | |
root->right = insert(root->right, data); | |
return root; | |
} | |
}; | |
//Function to visit nodes in preorder | |
template<typename T, typename F> | |
void preorder(struct Node<T> *root, F f) { | |
// base condition for recursion | |
// if tree/sub-tree is empty, return and exit | |
if (root == nullptr) return; | |
f(root); // Print data | |
preorder(root->left, f); // Visit left subtree | |
preorder(root->right, f); // Visit right subtree | |
} | |
//Function to visit nodes in inorder | |
template<typename T, typename F> | |
void inorder(Node<T> *root, F f) { | |
if (root == nullptr) return; | |
inorder(root->left, f); //Visit left subtree | |
f(root); // Print data | |
inorder(root->right, f); // Visit right subtree | |
} | |
//Function to visit nodes in postorder | |
template<typename T, typename F> | |
void postorder(Node<T> *root, F f) { | |
if (root == nullptr) return; | |
postorder(root->left, f); // Visit left subtree | |
postorder(root->right, f); // Visit right subtree | |
f(root); // Print data | |
} | |
/* | |
Test on an example tree of Node<char> | |
0 | |
/ \ | |
1 2 | |
/ \ \ | |
3 4 5 | |
*/ | |
void test(std::wostream & wos ) { | |
const wchar_t & nl = { L'\n' }; | |
typedef Node<char> NodeT; | |
typedef void(*Node_printer) (NodeT *); | |
/* tree imp operates with naked pointers | |
that makes it more obvious what is goin on | |
*/ | |
NodeT * root{} ; | |
/* | |
this lambda is our processor | |
it can be any lambda, function or functor that receives pointer to Node<> instance | |
and returns void. | |
That means in this implementation the whole tree will be always visited. There is no | |
retval from the processor to stop the processing. | |
*/ | |
auto printF = [](NodeT * x) { printf("%c ", x->data); }; | |
/*root = NodeT::insert(root, '0'); */ | |
root = NodeT::insert(root, '0'); root = NodeT::insert(root, '1'); | |
root = NodeT::insert(root, '3'); root = NodeT::insert(root, '2'); | |
root = NodeT::insert(root, '5'); root = NodeT::insert(root, '4'); | |
NodeT::NodeP smart = root->smart(); | |
wos << nl << L"Process then visit left and right: "; | |
preorder(root, printF); | |
wos << nl; | |
wos << nl << L"Visit left, Process then visit right: "; | |
inorder(root, printF); | |
wos << nl; | |
wos << nl << L"Visit left, visit right then Process: "; | |
postorder(root, printF); | |
wos << nl; | |
// after this point smart_root deletes the tree; | |
} | |
} // tree | |
} // dbj |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment