#pragma warning(disable : 4996)
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
template <typename T>
struct BinNode {
int _depth;
int _height;
T _data;
BinNode* _parent;
BinNode* _lChild;
BinNode* _rChild;
template <typename VST> static void visitAlongLeftBranch(BinNode* x, VST&, std::stack<BinNode*>& s);
template <typename VST> static void goAlongLeftBranch(BinNode* x, VST& visit, std::stack<BinNode<T>*>& s);
static void gotoLeftmostLeaf(std::stack<BinNode<T>*>& s);
public:
BinNode();
BinNode(const T& data);
int size() const;
BinNode* succ() const;
template <typename VST> void travLevel(VST&);
template <typename VST> void travPre(VST&);
template <typename VST> static void travPre_I2(BinNode* x,VST&);
template <typename VST> void travIn(VST&);
template <typename VST> static void travIn_I1(BinNode* x, VST&);
template <typename VST> void travPost(VST&);
template <typename VST> static void travPost_I(BinNode* x, VST&);
};
template <typename T>
BinNode<T>::BinNode() : _depth(0), _height(0), _data(T()), _parent(nullptr), _lChild(nullptr), _rChild(nullptr) {}
template <typename T>
BinNode<T>::BinNode(const T& data) : _depth(0), _height(0), _data(data), _parent(nullptr), _lChild(nullptr), _rChild(nullptr) {}
template <typename T>
int BinNode<T>::size() const {
return (_lChild ? _lChild->size() : 0) + (_rChild ? _rChild->size() : 0) + 1;
}
template <typename T>
BinNode<T>* BinNode<T>::succ() const {
BinNode<T>* p = const_cast<BinNode<T>*>(this);
if (_rChild) {
p = _rChild;
while (p->_lChild) p = p->_lChild;
}
else {
while (p->_parent && p == p->_parent->_rChild) p = p->_parent;
p = p->_parent;
}
return p;
}
template <typename T>
template <typename VST>
void BinNode<T>::travLevel(VST& visit) {
std::queue<BinNode<T>*> q;
q.push(this);
while (!q.empty()) {
BinNode<T>* x = q.front(); q.pop();
visit(x->_data);
if (x->_lChild) q.push(x->_lChild);
if (x->_rChild) q.push(x->_rChild);
}
}
template<typename T>
template<typename VST>
void BinNode<T>::goAlongLeftBranch(BinNode* x, VST& visit, std::stack<BinNode<T>*>& s)
{
while (x) {
s.push(x);
x = x->_lChild;
}
}
template<typename T>
static void BinNode<T>::gotoLeftmostLeaf(std::stack<BinNode<T>*>& s)
{
while (BinNode<T>* x = s.top()) {
if (x -> _lChild) {
if (x->_rChild) { s.push(x->_rChild); }
s.push(x->_lChild);
}
else{
s.push(x->_rChild);
}
}
s.pop();
}
template<typename T>
template<typename VST>
void BinNode<T>::visitAlongLeftBranch(BinNode* x, VST& visit, std::stack<BinNode<T>*>& s)
{
while (x) {
visit(x);
if(x->_rChild)
s.push(x ->_rChild);
x = x->_lChild;
}
}
template <typename T>
template <typename VST>
void BinNode<T>::travPre(VST& visit) {
std::stack<BinNode<T>*> s;
s.push(this);
while (!s.empty()) {
BinNode<T>* x = s.top();
s.pop();
visit(x->_data);
if (x->_rChild) s.push(x->_rChild);
if (x->_lChild) s.push(x->_lChild);
}
}
template<typename T>
template<typename VST>
static void BinNode<T>::travPre_I2(BinNode* x,VST& visit)
{
std::stack<BinNode *> s;
while (true) {
visitAlongLeftBranch(x, visit, s);
if (s.empty()) break;
x = s.top();
}
}
template <typename T>
template <typename VST>
void BinNode<T>::travIn(VST& visit) {
std::stack<BinNode<T>*> s;
BinNode<T>* current = this;
while (current != nullptr || !s.empty()) {
while (current != nullptr) {
s.push(current);
current = current->_lChild;
}
if (!s.empty()) {
current = s.top();
s.pop();
visit(current->_data);
current = current->_rChild;
}
}
}
template<typename T>
template<typename VST>
void BinNode<T>::travIn_I1(BinNode* x, VST& visit)
{
std::stack<BinNode<T>*> s;
while (true) {
goAlongLeftBranch(x, visit, s);
if (s.empty()) break;
x = s.top();
s.pop();
visit(x->_data);
x = x->_rChild;
}
}
template <typename T>
template <typename VST>
void BinNode<T>::travPost(VST& visit) {
std::stack<BinNode<T>*> s1, s2;
s1.push(this);
while (!s1.empty()) {
BinNode<T>* x = s1.top();
s1.pop();
s2.push(x);
if (x->_lChild) s1.push(x->_lChild);
if (x->_rChild) s1.push(x->_rChild);
}
while (!s2.empty()) {
visit(s2.top()->_data);
s2.pop();
}
}
template<typename T>
template<typename VST>
void BinNode<T>::travPost_I(BinNode* x, VST& visit)
{
std::stack<BinNode<T>*> s;
if (x) s.push(x);
while (!s.empty()) {
if (s.top() != x->_parent) {
gotoLeftmostLeaf(s);
}
x = s.top();
visit(x->_data);
s.pop();
}
}
template <typename T>
class BinTree {
protected:
int _size;
BinNode<T>* _root;
virtual int updateHeight(BinNode<T>* x);
void updateHeightAbove(BinNode<T>* x);
static void release(BinNode<T>* x);
virtual int updateDepth(BinNode<T>* x);
void updateDepthBelow(BinNode<T>* x);
public:
BinTree() : _size(0), _root(nullptr) {}
~BinTree();
int size() const { return _size; }
bool empty() const { return !_root; }
BinNode<T>* root() const { return _root; }
BinNode<T>* insertAsRoot(const T& elem);
BinNode<T>* insertAsLC(BinNode<T>* parent, const T& elem);
BinNode<T>* insertAsRC(BinNode<T>* parent, const T& elem);
};
template <typename T>
int BinTree<T>::updateHeight(BinNode<T>* x) {
return x->_height = 1 + std::max(x->_lChild ? x->_lChild->_height : -1,
x->_rChild ? x->_rChild->_height : -1);
}
template <typename T>
void BinTree<T>::updateHeightAbove(BinNode<T>* x) {
while (x) {
int oldHeight = x->_height;
updateHeight(x);
if (oldHeight == x->_height) {
break;
}
x = x->_parent;
}
}
template<typename T>
void BinTree<T>::release(BinNode<T>* root)
{
if (!root) return;
std::stack<BinNode<T>*> nodeStack;
nodeStack.push(root);
while (!nodeStack.empty()) {
BinNode<T>* node = nodeStack.top();
nodeStack.pop();
if (node->_rChild) nodeStack.push(node->_rChild);
if (node->_lChild) nodeStack.push(node->_lChild);
delete node;
}
}
template <typename T>
int BinTree<T>::updateDepth(BinNode<T>* x) {
if (x == nullptr) return -1;
x->_depth = x->_parent ? x->_parent->_depth + 1 : 0;
return x->_depth;
}
template <typename T>
void BinTree<T>::updateDepthBelow(BinNode<T>* x) {
if (x) {
int oldDepth = x->_depth;
updateDepth(x);
if (oldDepth == x->_depth) {
return;
}
updateDepthBelow(x->_lChild);
updateDepthBelow(x->_rChild);
}
}
template <typename T>
BinTree<T>::~BinTree() {
release(_root);
}
template <typename T>
BinNode<T>* BinTree<T>::insertAsRoot(const T& elem) {
_root = new BinNode<T>(elem);
_size = 1;
updateDepthBelow(_root);
return _root;
}
template <typename T>
BinNode<T>* BinTree<T>::insertAsLC(BinNode<T>* parent, const T& elem) {
if (!parent->_lChild) {
parent->_lChild = new BinNode<T>(elem);
parent->_lChild->_parent = parent;
_size++;
updateHeightAbove(parent);
updateDepthBelow(parent->_lChild);
return parent->_lChild;
}
return nullptr;
}
template <typename T>
BinNode<T>* BinTree<T>::insertAsRC(BinNode<T>* parent, const T& elem) {
if (!parent->_rChild) {
parent->_rChild = new BinNode<T>(elem);
parent->_rChild->_parent = parent;
_size++;
updateHeightAbove(parent);
updateDepthBelow(parent->_rChild);
return parent->_rChild;
}
return nullptr;
}
void visit(int& e) { std::cout << e << " "; }
int main() {
BinTree<int> tree;
BinNode<int>* root = tree.insertAsRoot(1);
BinNode<int>* leftChild = tree.insertAsLC(root, 2);
BinNode<int>* rightChild = tree.insertAsRC(root, 3);
tree.insertAsLC(leftChild, 4);
tree.insertAsRC(leftChild, 5);
tree.insertAsLC(rightChild, 6);
tree.insertAsRC(rightChild, 7);
std::cout << "Level Order: ";
root->travLevel(visit);
std::cout << "\nPre-order: ";
root->travPre(visit);
std::cout << "\nIn-order: ";
root->travIn(visit);
std::cout << "\nPost-order: ";
root->travPost(visit);
std::cout << std::endl;
return 0;
}