Post on 27-Dec-2015
transcript
Kruse/Ryba ch10 1
Object Oriented Data Structures
Binary TreesBinary Search Trees
Height Balance:AVL TreesSplay Trees
Kruse/Ryba ch10 2
Tournament Trees
A common form of tree used in everyday life is the tournament tree, used to describe the outcome of a series of games, such as a tennis tournament.Alice
AntoniaAnitaAbigailAmyAgnesAngelaAudrey
Alice
Abigail
Agnes
Angela
Alice
Angela
Alice
Kruse/Ryba ch10 3
A Family Tree
Much of the tree terminology derives from family trees. Gaea
Cronus Phoebe Ocean
Zeus Poseidon Demeter Pluto Leto Iapetus
Persephone Apollo Atlas Prometheus
Kruse/Ryba ch10 4
Ancestor Tree
An inverted family tree. Important point - it is a binary tree.
Iphigenia
Clytemnestra Agamemnon
Leda Tyndareus Aerope Atreus
Catreus
Kruse/Ryba ch10 5
Characteristics of Trees
A node with no children is a tree. Such a node is called a leaf.
A leaf node has height zero.
Kruse/Ryba ch10 6
Characteristics of Trees
A node with a non-empty collection of trees is a tree. The trees in the collection are known as the children of the node. The tree so constructed is in turn called the parent to the children trees. A tree with a non-empty set of children is called an interior node. The height of an interior node is one greater than the maximum height of any child.
Kruse/Ryba ch10 7
Characteristics of Trees
There is a single node with no parent, called the root of the tree.
Kruse/Ryba ch10 8
root
Kruse/Ryba ch10 9
root
interior interior
interior
Kruse/Ryba ch10 10
leaf
leaf
leaf
root
interior interior
interior
Kruse/Ryba ch10 11
leaf
leaf
leaf
root
interior interior
height 0
interior
height 2
Kruse/Ryba ch10 12
Legal Trees
Non-trees
Kruse/Ryba ch10 13
Trees & Subtrees
We will often talk of a subtree of a tree as if it is a tree.
Kruse/Ryba ch10 14
Height versus Number of Nodes
One of the most important characteristics of a binary tree is the number of nodes versus the height of a tree.
Height 01 node1 leaf
Height 13 nodes2 leaves
Height 27 nodes4 leaves
Kruse/Ryba ch10 15
Thin and Unbalanced Trees
The previous results were predicted on the tree being full. In a thin and unbalanced tree, the results need not hold.
This tree has height 3, but only four nodes.
Kruse/Ryba ch10 16
Complete Binary Tree
One way to ensure full trees is to make the trees be complete. This means the difference between longest and shortest paths is 1, and nodes are filled "left to right". A
B C
D E F G
H I J
Kruse/Ryba ch10 17
Complete Examples
Kruse/Ryba ch10 18
Examples: Not Complete
Kruse/Ryba ch10 19
Height versus Number of Nodes
A full binary tree of height h will have 2h leaves.The number of nodes in a full binary tree of height n is 2h+1 - 1
Kruse/Ryba ch10 20
Tree Traversals
Process a node.Recursively visit and process the left child.Recursively visit and process the right child.
Lists and Vectors have an obvious traversal order. For trees there is no such obvious ordering. Traversals are formed out of different combinations of:
Kruse/Ryba ch10 21
Four Important Traversals
preorder: value, left child, right childinorder: left child, value, right childpostorder: left child, right child, valuelevel order: sibling nodes by "level"
There are generally four important traversal orders:
Kruse/Ryba ch10 22
Traversals
23
18
6 19
21 22
42
35 56
Lets Practice
Kruse/Ryba ch10 23
Expression Trees
Built from simple operands and operators of an expression, placing the simple operands as the leaves of a binary tree with the operators as the interior nodes.
Kruse/Ryba ch10 24
x
:=
/
+ x
-
x
- 0.5b
a2
xb 2 c
a4What is the expression ?
Kruse/Ryba ch10 25
Linked Implementationtemplate <class Entry>class Binary_tree { public: // Add methods here.
protected: // Function prototypes here. Binary_node<Entry> *root;};
Kruse/Ryba ch10 26
template <class Entry>struct Binary_node {// data members: Entry data; Binary_node<Entry> *left; Binary_node<Entry> *right;// constructors: Binary_node(); Binary_node(const Entry &x);};
Kruse/Ryba ch10 27
template <class Entry>Binary_tree<Entry>::Binary_tree()/*Post: An empty binary tree has been created.*/
{
root = NULL;
}
Kruse/Ryba ch10 28
template <class Entry>bool Binary_tree<Entry>::empty()/*Post: True returned if empty, false otherwise*/
{
return root == NULL;
}
Kruse/Ryba ch10 29
template <class Entry>class Binary_tree { public: Binary_tree(); bool empty() const; void preorder(void (*visit)(Entry &)); void inorder(void (*visit)(Entry &)); void postorder(void (*visit)(Entry &)); int size() const; void clear(); int height() const; void insert(const Entry &); Binary_tree (const Binary_tree<Entry> &original); Binary_tree & operator = (const Binary_tree<Entry> &original); ~Binary_tree(); protected: // Add auxiliary function prototypes here. Binary_node<Entry> *root;};
Kruse/Ryba ch10 30
Traversals as Recursive Procedurestemplate <class Entry>void Binary_tree<Entry>::recursive_inorder(Binary_node<Entry> *sub_root, void (*visit)(Entry &)) { if (sub_root != NULL) { recursive_inorder(sub_root->left, visit); (*visit)(sub_root->data); recursive_inorder(sub_root->right, visit); } }
Kruse/Ryba ch10 31
Traversals as Recursive Procedurestemplate <class Entry>void Binary_tree<Entry>::recursive_preorder(Binary_node<Entry> *sub_root, void (*visit)(Entry &)) { if (sub_root != NULL) {
(*visit)(sub_root->data); recursive_preorder(sub_root->left, visit); recursive_preorder(sub_root->right, visit); } }
Kruse/Ryba ch10 32
Traversals as Recursive Procedurestemplate <class Entry>void Binary_tree<Entry>::recursive_postorder(Binary_node<Entry> *sub_root, void (*visit)(Entry &)) { if (sub_root != NULL) { recursive_postorder(sub_root->left, visit); recursive_postorder(sub_root->right, visit); (*visit)(sub_root->data); } }
Kruse/Ryba ch10 33
A Binary Search Tree is a binary tree that is either empty or in which every node has a key (within its data entry) and satisfies the following conditions:
The key of the root (if it exists) is greater than the key in any node in the left subtree of the root.The key of the root (if it exists) is less than the key in any node in the right subtree of the root.The left and right subtrees of the root are again binary search trees.
Binary Search Tree
Kruse/Ryba ch10 34
23
18
6 20
19 22
42
35 56
Binary Search Tree
No two entries may have equal keys
Kruse/Ryba ch10 35
Three Points of View
We can regard binary search trees as a new abstract data type with its own definition and its own methodsSince binary search trees are special kinds of binary trees, we may consider their methods as special kinds of binary tree methods.Since the entries in binary search trees contain keys, and since they are applied for information retrieval in the same way as ordered lists, we may study binary search trees as a new implementation of the abstract data type ordered list.
Kruse/Ryba ch10 36
The Solutiontemplate <class Record>class Search_tree: public Binary_tree<Record> { public: Error_code insert(const Record &new_data); Error_code remove(const Record &old_data); Error_code tree_search(Record &target) const; private: // Add aux prototypes here.
};
Kruse/Ryba ch10 37
Tree Search
Error_code Search_tree<Record>::tree_search(Record & target) const;
postcondition: If there is an entry in the tree whose key matches that in target, the parameter target is replaced by the corresponding record from the tree and a code of success is returned. Otherwise a code of not_present is returned.
Kruse/Ryba ch10 38
Search_for_node
Binary_node<Record>*Search_tree<Record>::search_for_node(Binary_node<Record>*sub_root, const Record & target) const;
Preconditions: sub_root is either NULL or points to a subtree of a Search_tree
Postconditions: If the key of target is not in the subtree, a result of NULL is returned. Otherwise, a pointer to the subtree node containing the target is returned.
Kruse/Ryba ch10 39
Recursive Versiontemplate <class Record>Binary_node<Record> *Search_tree<Record>:: search_for_node( Binary_node<Record>* sub_root, const Record &target) const{ if (sub_root == NULL || sub_root->data == target) return sub_root; else if (sub_root->data < target) return search_for_node(sub_root->right, target); else return search_for_node(sub_root->left, target);
}
Kruse/Ryba ch10 40
Iterative Version
template <class Record>Binary_node<Record> *Search_tree<Record>::search_for_node(Binary_node<Record> *sub_root, const Record &target) const{ while (sub_root!=NULL && sub_root->data!=target) if (sub_root->data < target) sub_root = sub_root->right; else sub_root = sub_root->left;
return sub_root;}
Kruse/Ryba ch10 41
tree_search()template <class Record>Error_code Search_tree<Record>:: tree_search(Record &target) const { Error_code result = success; Binary_node<Record> *found = search_for_node(root, target); if (found == NULL) result = not_present; else target = found->data; return result;}
Kruse/Ryba ch10 42
Insertion
template <class Record>
Error_code Search_tree<Record>::insert(const Record &new_data)
{
return search_and_insert(root, new_data);
}
Kruse/Ryba ch10 43
Tree Sort
23
14
17
29
26
10
23
14
17
29
2610
10
14
17
23
26
29
Process: Build a binary search tree and then traverse in-order.
Input Binary search tree Sorted List
Kruse/Ryba ch10 44
23
18
6 20
19 22
42
35 56
Removing a Node
Kruse/Ryba ch10 45
Removing a Node
23
18
6 20
22
42
35 56
New Link
Kruse/Ryba ch10 46
23
18
6 20
19 22
42
35
How it looks after deletion?
Kruse/Ryba ch10 47
23
18
6 20
19 22
42
35 56
Removing a Node
New Links
One possible solution
Kruse/Ryba ch10 48
23
6
20
19 22
42
35
Kruse/Ryba ch10 49
template <class Record>Error_code Search_tree<Record>::search_and_insert(Binary_node<Record> *&sub_root, const Record &new_data){ if (sub_root == NULL) { sub_root = new Binary_node<Record>(new_data); return success; } else if (new_data < sub_root->data) return search_and_insert(sub_root->left, new_data); else if (new_data > sub_root->data) return search_and_insert(sub_root->right, new_data); else return duplicate_error;}
Kruse/Ryba ch10 50
template <class Record>Error_code Search_tree<Record>::remove(const Record &target)/*Post: If a Record with a key matching that of target belongs to the Search_tree, a code of success is returned and the corresponding node is removed from the tree. Otherwise, a code of not_present is returned.
Uses: Function search_and_destroy*/{
return search_and_destroy(root, target);
}
Kruse/Ryba ch10 51
template <class Record>Error_code Search_tree<Record>:: search_and_destroy(Binary_node<Record>* &sub_root, const Record &target)
{ if (sub_root == NULL || sub_root->data == target) return remove_root(sub_root); else if (target < sub_root->data) return search_and_destroy(sub_root->left, target); else return search_and_destroy(sub_root->right, target);}
Kruse/Ryba ch10 52
template <class Record>Error_code Search_tree<Record>::remove_root(Binary_node<Record> *&sub_root){ if (sub_root == NULL) return not_present; Binary_node<Record> *to_delete = sub_root; if (sub_root->right == NULL) sub_root = sub_root->left; else if (sub_root->left == NULL) sub_root = sub_root->right; else { // Neither subtree is empty. to_delete = sub_root->left; // Move left to find predecessor. Binary_node<Record> *parent = sub_root; // parent of to_delete while (to_delete->right != NULL) { parent = to_delete; to_delete = to_delete->right; } sub_root->data = to_delete->data; // Move from to_delete to root
if (parent == sub_root) sub_root->left = to_delete->left; else parent->right = to_delete->left; } delete to_delete; // Remove to_delete from tree. return success;}
Kruse/Ryba ch10 53
Building a Balanced BST
'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j'1 2 3 4 5 6 7 8 9 10
'k'11
Whether creating from a list, vector or file it is not unreasonable to assume that the number of entries is know.
Kruse/Ryba ch10 54
Building a BST
'a'1
'c'3
'e'5
'g'7
'i'9
'b'2
'd'4
'f'6
'h'8
'j'10
'k'11
200
1 21
Kruse/Ryba ch10 55
Building a BST
'a'1
'c'3
'e'5
'g'7
'i'9
'b'2
'd'4
'f'6
'h'8
'j'10
'k'11
200
1 21
2 22
Kruse/Ryba ch10 56
Building a BST
'a'1
'c'3
'e'5
'g'7
'i'9
'b'2
'd'4
'f'6
'h'8
'j'10
'k'11
200
1 21
2 22
3 23
Kruse/Ryba ch10 57
Building a BST
'a'1
'c'3
'e'5
'g'7
'i'9
'b'2
'd'4
'f'6
'h'8
'j'10
'k'11
200
1 21
2 22
3 23
Kruse/Ryba ch10 58
Buildable Tree
template <class Record>class Buildable_tree: public Search_tree<Record> { public: Error_code build_tree( const List<Record> &supply);
private: // Add auxiliary function prototypes // here.
};
Kruse/Ryba ch10 59
template <class Record>Error_code Buildable_tree<Record>::build_tree(const List<Record> &supply){ Error_code ordered_data = success; // Fail if keys do not increase. int count = 0; // number of entries inserted so far Record x, last_x; List<Binary_node<Record> *> last_node; // pointers to last nodes on each level Binary_node<Record> *none = NULL; last_node.insert(0, none); // permanently NULL (for children of leaves)
Kruse/Ryba ch10 60
while (supply.retrieve(count, x) == success) { if (count > 0 && x <= last_x) { ordered_data = fail; break; } build_insert(++count, x, last_node); last_x = x; } root = find_root(last_node); connect_trees(last_node); return ordered_data; // Report data-ordering problems to client.
}
Kruse/Ryba ch10 61
template <class Record>void Buildable_tree<Record>::build_insert(int count, const Record &new_data, List<Binary_node<Record>*> &last_node){ int level; // level of new node above the leaves for (level = 1; count % 2 == 0; level++) count /= 2; // Use count to calculate level of next_node. Binary_node<Record> *next_node = new Binary_node<Record>(new_data),*parent; // one level higher in last_node last_node.retrieve(level - 1, next_node->left); if (last_node.size() <= level) last_node.insert(level, next_node); else last_node.replace(level, next_node); if (last_node.retrieve(level + 1, parent) == success && parent->right == NULL) parent->right = next_node;}
Kruse/Ryba ch10 62
And the root?
template <class Record>Binary_node<Record> *Buildable_tree<Record>::find_root(List<Binary_node<Record>*> &last_node){ Binary_node<Record> *high_node; last_node.retrieve(last_node.size() - 1, high_node); // Find root in the highest occupied // level in last_node. return high_node;}
Kruse/Ryba ch10 63
template <class Record>void Buildable_tree<Record>::connect_trees(const List<Binary_node<Record>*> &last_node)/*Pre: The nearly-completed binary search tree has been initialized. The List last_node has been initialized and contains links to the last node on each level of the tree.
Post: The final links have been added to complete the binary search tree.
Uses: Methods of class List*/{ Binary_node<Record> *high_node, // from last_node with NULL right child *low_node; // candidate for right child of high_node int high_level = last_node.size() - 1, low_level;
Kruse/Ryba ch10 64
while (high_level > 2) { // Nodes on levels 1 and 2 are already OK. last_node.retrieve(high_level, high_node); if (high_node->right != NULL) high_level--; // Search down for highest dangling node. else { // Case: undefined right tree low_level = high_level;
// Find the highest entry not in the left subtree. do { last_node.retrieve(--low_level, low_node); } while (low_node != NULL && low_node->data < high_node->data);
high_node->right = low_node; high_level = low_level; } }}
Kruse/Ryba ch10
Obtaining Guaranteed Performance
Operations on search trees are proportional to the length of the path from root to leaf.
Unfortunately, in the worst case, this could be the same as the number of nodes in the tree (remember the thin unbalanced trees?)
To assure good performance, we need a way to make sure our trees are relatively "full".
12
34
56
Kruse/Ryba ch10
Height Balance Property
Associate with each node a value which is the difference between the longest path in the left child and the longest path in the right child.
A tree is height balanced if this value is never smaller than -1 or larger than 1.
4:1
2:0 6:1
1:0 3:0 5:0 15:0
7:0 16:0
Key_balance_factor
Kruse/Ryba ch10
AVL Trees
In 1962 two Russian mathematicians, G. M. Adel'son-Vel'skii and E. M. Landis, developed algorithms for the insertion and removal from height balanced trees so that the height balance property is maintained. The resulting binary search trees are named in their honor.
Kruse/Ryba ch10
AVL Trees
The key insight is that height balance can be restored through rotation. For example, assume we have inserted the value 3 into a tree containing 1 and 2.
1:2
2:1
3:01:0
2:0
3:0
Kruse/Ryba ch10
Double Rotation
Occasionally, a single rotation is not adequate. Consider the insertion of 15 into the following tree.
4:0
2:0 6:0
1:0 3:0 5:0 7:1
16:0
Kruse/Ryba ch10
Double Rotation
The solution is a pair of rotations, called a double rotation
4:2
2:0 6:2
1:0 3:0 5:0 7:2
16:-1
15:0
Kruse/Ryba ch10
Double Rotation
The solution is a pair of rotations, called a double rotation
4:2
2:0 6:2
1:0 3:0 5:0 7:2
16:-1
15:0
4:2
2:0 6:2
1:0 3:0 5:0 7:2
15:1
16:0
First: rotate the child subtree right.
Kruse/Ryba ch10
Double Rotation
The solution is a pair of rotations, called a double rotation
4:2
2:0 6:2
1:0 3:0 5:0 7:2
15:0
16:0
4:1
2:0 6:1
1:0 3:0 5:0 15:0
16:07:0Then, rotate the parent subtree left.
Kruse/Ryba ch10
Addition & Removal Algorithms
Move down to the correct location where insertion is to be performedInsert new element, which may cause things to become unbalancedMove back up tree, performing rotations to make sure tree becomes balanced once again.
The addition algorithm is then roughly as follows:
Kruse/Ryba ch10 74
template <class Record>struct AVL_node: public Binary_node<Record> {// additional data member: Balance_factor balance = equal_height;
// constructors: AVL_node(); AVL_node(const Record &x);
// overridden virtual functions: void set_balance(Balance_factor b);
Balance_factor get_balance() const;
};
Kruse/Ryba ch10 75
template <class Record>void AVL_node<Record>::set_balance(Balance_factor b){
balance = b;
}
template <class Record>Balance_factor AVL_node<Record>::get_balance() const{
return balance;
}
Kruse/Ryba ch10 76
template <class Entry>struct Binary_node {// data members: Entry data; Binary_node<Entry> *left; Binary_node<Entry> *right;
// constructors: Binary_node(); Binary_node(const Entry &x);
// virtual methods: virtual void set_balance(Balance_factor b); virtual Balance_factor get_balance() const;
};
Kruse/Ryba ch10 77
template <class Record>class AVL_tree: public Search_tree<Record> {
public: Error_code insert(const Record &new_data);
Error_code remove(const Record &old_data);
private: // Add auxiliary function prototypes here.
};
Kruse/Ryba ch10 78
template <class Record>Error_code AVL_tree<Record>::insert(const Record &new_data)/*Post: If the key of new_data is already in the AVL_tree, a code of duplicate_error is returned. Otherwise, a code of success is returned and the Record new_data is inserted into the tree in such a way that the properties of an AVL tree are preserved.
Uses: avl_insert.*/{ bool taller; return avl_insert(root, new_data, taller);}
Kruse/Ryba ch10 79
template <class Record>Error_code AVL_tree<Record>::avl_insert(Binary_node<Record> *&sub_root, const Record &new_data, bool &taller)
/*Pre: sub_root is either NULL or points to a subtree of the AVL_tree
Post: If the key of new_data is already in the subtree, a code of duplicate_error is returned.Otherwise, a code of success is returned and the Record new_data is inserted into the subtree in such a way that the properties of an AVL tree have been preserved. If the subtree is increased in height, the parameter taller is set to true; otherwise it is set to false.
Uses: Methods of struct AVL_node; functions avl_insert recursively, left_balance, and right_balance.
*/
Kruse/Ryba ch10 80
{
Error_code result = success;
if (sub_root == NULL) { sub_root = new AVL_node<Record>(new_data); taller = true; }
else if (new_data == sub_root->data) { result = duplicate_error; taller = false; }
else if (new_data < sub_root->data) { // Insert in left subtree. result = avl_insert(sub_root->left, new_data, taller); if (taller == true) switch (sub_root->get_balance()) { // Change balance factors.
Kruse/Ryba ch10 81
case left_higher:
left_balance(sub_root);
taller = false; // Rebalancing always shortens the tree.
break;
case equal_height:
sub_root->set_balance(left_higher);
break;
case right_higher:
sub_root->set_balance(equal_height);
taller = false;
break;
}// end switch
}// end insert in left subtree
Kruse/Ryba ch10 82
else { // Insert in right subtree. result = avl_insert(sub_root->right, new_data, taller); if (taller == true) switch (sub_root->get_balance()) { case left_higher: sub_root->set_balance(equal_height); taller = false; break; case equal_height: sub_root->set_balance(right_higher); break; case right_higher: right_balance(sub_root); taller = false; // Rebalancing always shortens the tree. break; } } return result;}
Kruse/Ryba ch10 83
template <class Record>void AVL_tree<Record>::rotate_left(Binary_node<Record> *&sub_root)/*Pre: sub_root points to a subtree of the AVL_tree. This subtree has a nonempty right subtree.Post: sub_root is reset to point to its former right child, and the former sub_root node is the left child of the new sub_root node.*/{ if (sub_root == NULL || sub_root->right == NULL) cout << "WARNING: program error detected in rotate_left" << endl; else { Binary_node<Record> *right_tree = sub_root->right; sub_root->right = right_tree->left; right_tree->left = sub_root; sub_root = right_tree; }}
Kruse/Ryba ch10 84
template <class Record>void AVL_tree<Record>::right_balance(Binary_node<Record> *&sub_root)
/*
Pre: sub_root points to a subtree of an AVL_tree that is doubly unbalanced on the right.
Post: The AVL properties have been restored to the subtree.
Uses: Methods of struct AVL_node; functions rotate_right and rotate_left.
*/
Kruse/Ryba ch10 85
{
Binary_node<Record> *&right_tree = sub_root->right;
switch (right_tree->get_balance()) {
case right_higher: // single rotation left
sub_root->set_balance(equal_height);
right_tree->set_balance(equal_height);
rotate_left(sub_root);
break;
case equal_height: // impossible case
cout << "WARNING: program error detected in right_balance" << endl;
Kruse/Ryba ch10 86
case left_higher: // double rotation left Binary_node<Record> *sub_tree = right_tree->left; switch (sub_tree->get_balance()) { case equal_height: sub_root->set_balance(equal_height); right_tree->set_balance(equal_height); break; case left_higher: sub_root->set_balance(equal_height); right_tree->set_balance(right_higher); break; case right_higher: sub_root->set_balance(left_higher); right_tree->set_balance(equal_height); break; } sub_tree->set_balance(equal_height); rotate_right(right_tree); rotate_left(sub_root); break; }}
Kruse/Ryba ch10 87
Splay Trees
Binary Search Trees that self-adjust to bring records closer to the root as they are more frequently accessed, allowing inactive records to drift slowly out toward the leaves.
Kruse/Ryba ch10 88
zig
zig
T1 T2
T3
T4
Kruse/Ryba ch10 89
zig
T4
T3
T1 T2
Kruse/Ryba ch10 90
zig
T1 T2T3 T4
Kruse/Ryba ch10 91
T1 T2T3 T4
Kruse/Ryba ch10 92
T1
T2
T3 T4
Kruse/Ryba ch10 93
T1
T2
T3 T4
Kruse/Ryba ch10 94
Binary Tree Representation of General Trees
An interesting fact to note is that binary trees can be used to represent general trees.
A
B C D
E F G H I
Left pointer is "eldest" child, right pointer is sibling. In this fashion, any tree can be written as a binary tree.
A
B
E F G H I J
C D
J
Kruse/Ryba ch10 95
General Tree
A
B
E F G H I J
C D
A
B
C
DGE
F H
I
J
Kruse/Ryba ch10 96
Postorder Tree Traversaltemplate <class T>postTT<T>::postTT(node<T> * root) // initialize postorder tree traversal iter{ current = root; // slide left to find leftmost descendant while(true){
while (current && current->leftChild) current = current->leftChild; if (current -> rightChile) current = current->rightChild; else break;
}}
Kruse/Ryba ch10 97
Postorder Tree Traversal ++
template <class T>postTT<T> & postTT<T>::operator ++() // increment for postorder traversal{ node<T> * child = current; current = current->parent; while(current && current->rightChild && current->rightChild != child){
current=current->rightChild; while(current->leftChild) //left slide current = current->leftChild;} return *this; //return ourselves}
Kruse/Ryba ch10 98
Chapter 10 Fades Away