Kruse/Ryba ch101 Object Oriented Data Structures Binary Trees Binary Search Trees Height Balance:AVL...

Post on 27-Dec-2015

221 views 1 download

Tags:

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