#include #include #include #include #include #include using namespace std; #include "recursive_generator.h" template struct BinaryTree; // todo: refactor to refer to parent instead of entire tree template struct Node { T value = T(); Node *left = nullptr; Node *right = nullptr; Node *parent = nullptr; BinaryTree* tree = nullptr; explicit Node(const T& value) : value(value) { } Node(const T& value, Node* const left, Node* const right) : value(value), left(left), right(right) { this->left->tree = this->right->tree = tree; this->left->parent = this->right->parent = this; } void set_tree(BinaryTree* t) { tree = t; if (left) left->set_tree(t); if (right) right->set_tree(t); } ~Node() { if (left) delete left; if (right) delete right; } }; template struct BinaryTree { Node* root = nullptr; explicit BinaryTree(Node* const root) : root{ root }, pre_order{ *this } { root->set_tree(this); } ~BinaryTree() { if (root) delete root; } template struct PreOrderIterator { Node* current; explicit PreOrderIterator(Node* current) : current(current) { } bool operator!=(const PreOrderIterator& other) { return current != other.current; } // no continuations in C++ (unlike C#) PreOrderIterator& operator++() { if (current->right) { current = current->right; while (current->left) current = current->left; } else { Node* p = current->parent; while (p && current == p->right) { current = p; p = p->parent; } current = p; } return *this; } Node& operator*() { return *current; } }; typedef PreOrderIterator iterator; iterator end() { return iterator{ nullptr }; } iterator begin() { Node* n = root; if (n) while (n->left) n = n->left; return iterator{ n }; } // expose as a traversal object // todo: make this inorder class pre_order_traversal { BinaryTree& tree; public: pre_order_traversal(BinaryTree& tree) : tree{tree} {} iterator begin() { return tree.begin(); } iterator end() { return tree.end(); } } pre_order; // todo: postorder iterator using recursive coroutines experimental::generator*> post_order() { return post_order_impl(root); } private: // or use a recursive_generator experimental::generator*> post_order_impl(Node* node) { if (node) { for (auto x : post_order_impl(node->left)) co_yield x; for (auto y : post_order_impl(node->right)) co_yield y; co_yield node; } } }; void std_iterators() { vector names{ "john", "jane", "jill", "jack" }; vector::iterator it = names.begin(); // or begin(names) cout << "first name is " << *it << "\n"; ++it; // advance the iterator it->append(string(" goodall")); cout << "second name is " << *it << "\n"; while (++it != names.end()) { cout << "another name: " << *it << "\n"; } // traversing the entire vector backwards // note global rbegin/rend, note ++ not -- // expand auto here for (auto ri = rbegin(names); ri != rend(names); ++ri) { cout << *ri; if (ri + 1 != rend(names)) // iterator arithmetic cout << ", "; } cout << endl; // constant iterators vector::const_reverse_iterator jack = crbegin(names); // won't work //*jack += "test"; } // in order traversal void binary_tree_iterator() { // me // / \ // mother father // / \ // m'm m'f BinaryTree family{ new Node{"me", new Node{"mother", new Node{"mother's mother"}, new Node{"mother's father"} }, new Node{"father"} } }; // pre order traversal for (auto it = family.begin(); it != family.end(); ++it) { cout << (*it).value << "\n"; } cout << "=== and now, through a dedicated object:\n"; // use iterator name for (const auto& it: family.pre_order) { cout << it.value << "\n"; } cout << "=== postorder travesal with coroutines:\n"; // use coroutines (yields pointers!) // postorder: m'm, m'f m f me for (auto it: family.post_order()) { cout << it->value << endl; } } int main() { //std_iterators(); binary_tree_iterator(); getchar(); return 0; }