Sei sulla pagina 1di 199

Binary Trees

Tree Data Structures


There are a number of applications where linear data structures are not appropriate. Consider a genealogy tree of a family.
Mohammad Aslam Khan

Sohail Aslam

Javed Aslam

Yasmeen Aslam

Haaris

Saad

Qasim

Asim

Fahd

Ahmad

Sara

Omer

Tree Data Structure


A linear linked list will not be able to capture the tree-like relationship with ease. Shortly, we will see that for applications that require searching, linear data structures are not suitable. We will focus our attention on binary trees.

Binary Tree
A binary tree is a finite set of elements that is either empty or is partitioned into three disjoint subsets. The first subset contains a single element called the root of the tree. The other two subsets are themselves binary trees called the left and right subtrees. Each element of a binary tree is called a node of the tree.

Binary Tree
Binary tree with 9 nodes.
A B C

Binary Tree
root A B C

Left subtree

Right subtree

Binary Tree
Recursive definition
A root B C

Left subtree

Right subtree

Binary Tree
Recursive definition
A B root D E C

Left subtree

Binary Tree
Recursive definition
A B C

E root G

Binary Tree
Recursive definition
A root B C

Right subtree

Binary Tree
Recursive definition
A B C root D E

Left subtree

Right subtree

Not a Tree
Structures that are not trees.
A B C

Not a Tree
Structures that are not trees.
A B C

Not a Tree
Structures that are not trees.
A B C

Binary Tree: Terminology


parent A Left descendant B C Right descendant

Leaf nodes

Leaf nodes

Binary Tree
If every non-leaf node in a binary tree has non-empty left and right subtrees, the tree is termed a strictly binary tree.

A B C

Level of a Binary Tree Node


The level of a node in a binary tree is defined as follows:
Root has level 0, Level of any other node is one more than the level its parent (father).

The depth of a binary tree is the maximum level of any leaf in the tree.

Level of a Binary Tree Node

A B 1

Level 0

C 1

Level 1

D 2

E 2

F 2

Level 2

G 3

H 3

Level 3

Complete Binary Tree


A complete binary tree of depth d is the strictly binary all of whose leaves are at level d.
A B 1
0

C 1

D 2

E 2

F 2

G 2

H 3

J 3

L 3

M 3

N 3

O 3

Complete Binary Tree


A
B C
Level 0: 20 nodes Level 1: 21 nodes

Level 2: 22 nodes

Level 3: 23 nodes

Complete Binary Tree


At level k, there are 2k nodes. Total number of nodes in the tree of depth d: 20+ 21+ 22 + . + 2d = 2j = 2d+1 1
j=0 d

In a complete binary tree, there are 2d leaf nodes and (2d - 1) non-leaf (inner) nodes.

Complete Binary Tree


If the tree is built out of n nodes then n = 2d+1 1 or log2(n+1) = d+1 or d = log2(n+1) 1 I.e., the depth of the complete binary tree built using n nodes will be log2(n+1) 1. For example, for n=1,000,000, log2(1000001) is less than 20; the tree would be 20 levels deep. The significance of this shallowness will become evident later.

Operations on Binary Tree


There are a number of operations that can be defined for a binary tree. If p is pointing to a node in an existing tree then
left(p) returns pointer to the left subtree right(p) returns pointer to right subtree parent(p) returns the father of p brother(p) returns brother of p. info(p) returns content of the node.

Operations on Binary Tree


There are a number of operations that can be defined for a binary tree. If p is pointing to a node in an existing tree then
left(p) returns pointer to the left subtree right(p) returns pointer to right subtree parent(p) returns the father of p brother(p) returns brother of p. info(p) returns content of the node.

Operations on Binary Tree


In order to construct a binary tree, the following can be useful: setLeft(p,x) creates the left child node of p. The child node contains the info x. setRight(p,x) creates the right child node of p. The child node contains the info x.

Applications of Binary Trees


A binary tree is a useful data structure when two-way decisions must be made at each point in a process.

For example, suppose we wanted to find all duplicates in a list of numbers:


14, 15, 4, 9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Applications of Binary Trees


One way of finding duplicates is to compare each number with all those that precede it.
14, 15, 4, 9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5

14, 15, 4, 9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


If the list of numbers is large and is growing, this procedure involves a large number of comparisons. A linked list could handle the growth but the comparisons would still be large. The number of comparisons can be drastically reduced by using a binary tree. The tree grows dynamically like the linked list.

Searching for Duplicates


The binary tree is built in a special way. The first number in the list is placed in a node that is designated as the root of a binary tree. Initially, both left and right subtrees of the root are empty. We take the next number and compare it with the number placed in the root. If it is the same then we have a duplicate.

Searching for Duplicates


Otherwise, we create a new tree node and put the new number in it. The new node is made the left child of the root node if the second number is less than the one in the root. The new node is made the right child if the number is greater than the one in the root.

Searching for Duplicates


14

14, 15, 4, 9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


15 14

15, 4, 9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


14 15

15, 4, 9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


4 14 15

4, 9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


14 4 15

4, 9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


9 4 14 15

9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


14 4 15

9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


7 4 14 15

7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


14 4 15

9
7

7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


18 4 14 15

9
7

18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


14 4 15

9
7

18

18, 3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


3 4 14 15

9
7

18

3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


14 4 15

3
7

18

3, 5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


5 4 14 15

3
7

18

5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


14 4 15

3
7

18

5, 16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


16 4 14 15

3
7

18

16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


14 4 15

3
7

9
16

18

16, 4, 20, 17, 9, 14, 5

Searching for Duplicates


4 4 14 15

3
7

9
16

18

4, 20, 17, 9, 14, 5

Searching for Duplicates


20 4 14 15

3
7

9
16

18

20, 17, 9, 14, 5

Searching for Duplicates


14 4 15

3
7

9
16

18
20

20, 17, 9, 14, 5

Searching for Duplicates


17 4 14 15

3
7

9
16

18
20

17, 9, 14, 5

Searching for Duplicates


14 4 15

3
7

9
16

18
20

17

17, 9, 14, 5

Searching for Duplicates


14 4 15

3
7

9
16

18
20

17

9, 14, 5

C++ Implementation
#include <stdlib.h> template <class Object> class TreeNode { public: // constructors TreeNode() { this->object = NULL; this->left = this->right = NULL; }; TreeNode( Object* object ) { this->object = object; this->left = this->right = NULL; };

C++ Implementation
Object* getInfo() { return this->object; }; void setInfo(Object* object) { this->object = object; }; TreeNode* getLeft() { return left; }; void setLeft(TreeNode *left) { this->left = left; };

C++ Implementation
TreeNode *getRight() { return right; }; void setRight(TreeNode *right) { this->right = right; }; int isLeaf( ) { if( this->left == NULL && this->right == NULL ) return 1; return 0; };

C++ Implementation
private: Object* TreeNode* TreeNode* }; // end class object; left; right; TreeNode

C++ Implementation
#include <iostream> #include <stdlib.h> #include "TreeNode.cpp" int main(int argc, char *argv[]) { int x[] = { 14, 15, 4, 9, 7, 18, 3, 5, 16,4, 20, 17, 9, 14,5, -1}; TreeNode<int>* root = new TreeNode<int>(); root->setInfo( &x[0] ); for(int i=1; x[i] > 0; i++ ) { insert(root, &x[i] ); } }

C++ Implementation
void insert(TreeNode<int>* root, int* info) { TreeNode<int>* node = new TreeNode<int>(info); TreeNode<int> *p, *q; p = q = root; while( *info != *(p->getInfo()) && q != NULL ) { p = q; if( *info < *(p->getInfo()) ) q = p->getLeft(); else q = p->getRight(); }

C++ Implementation
if( *info == *(p->getInfo()) ){ cout << "attempt to insert duplicate: " << *info << endl; delete node; } else if( *info < *(p->getInfo()) ) p->setLeft( node ); else p->setRight( node ); } // end of insert

Trace of insert
17 4

p q

14 15

3
7

9
16

18
20

17, 9, 14, 5

Trace of insert
17 4

14

q
9
7

15

18
16 20

17, 9, 14, 5

Trace of insert
17 4 14

p q
9
7

15

18
16 20

17, 9, 14, 5

Trace of insert
17 4 14

p
9
7

15

q
16

18
20

17, 9, 14, 5

Trace of insert
17 4 14 15

3
7

p q
16

18
20

17, 9, 14, 5

Trace of insert
17 4 14 15

3
7

p
q
16

18
20

17, 9, 14, 5

Trace of insert
17 4 14 15

3
7

18

p q

16

20

17, 9, 14, 5

Trace of insert
17 4 14 15

3
7

18

16

20

17, 9, 14, 5

Trace of insert
14 4 15

3
7

18

16 node

20

17

17, 9, 14, 5

p->setRight( node );

Trace of insert
14 4 15

3
7

18

16 node

20

17

17, 9, 14, 5

p->setRight( node );

Cost of Search
Given that a binary tree is level d deep. How long does it take to find out whether a number is already present? Consider the insert(17) in the example tree. Each time around the while loop, we did one comparison. After the comparison, we moved a level down.

Cost of Search
With the binary tree in place, we can write a routine find(x) that returns true if the number x is present in the tree, false otherwise. How many comparison are needed to find out if x is present in the tree? We do one comparison at each level of the tree until either x is found or q becomes NULL.

Cost of Search
If the binary tree is built out of n numbers, how many comparisons are needed to find out if a number x is in the tree? Recall that the depth of the complete binary tree built using n nodes will be log2(n+1) 1. For example, for n=100,000, log2(100001) is less than 20; the tree would be 20 levels deep.

Cost of Search
If the tree is complete binary or nearly complete, searching through 100,000 numbers will require a maximum of 20 comparisons. Or in general, approximately log2(n). Compare this with a linked list of 100,000 numbers. The comparisons required could be a maximum of n.

Binary Search Tree


A binary tree with the property that items in the left subtree are smaller than the root and items are larger or equal in the right subtree is called a binary search tree (BST). The tree we built for searching for duplicate numbers was a binary search tree. BST and its variations play an important role in searching algorithms.

Traversing a Binary Tree


Suppose we have a binary tree, ordered (BST) or unordered. We want to print all the values stored in the nodes of the tree. In what order should we print them?

Traversing a Binary Tree


Ways to print a 3 node tree:
14

15

(4, 14, 15), (4,15,14) (14,4,15), (14,15,4) (15,4,14), (15,14,4)

Traversing a Binary Tree


In case of the general binary tree:
N node

L left subtree
(L,N,R), (L,R,N) (N,L,R), (N,R,L) (R,L,N), (R,N,L)

right R subtree

Traversing a Binary Tree


Three common ways
N node

left subtree

right subtree R

Preorder: (N,L,R) Inorder: (L,N,R) Postorder: (L,R,N)

Traversing a Binary Tree


void preorder(TreeNode<int>* treeNode) { if( treeNode != NULL ) { cout << *(treeNode->getInfo())<<" "; preorder(treeNode->getLeft()); preorder(treeNode->getRight()); } }

Traversing a Binary Tree


void inorder(TreeNode<int>* treeNode) { if( treeNode != NULL ) { inorder(treeNode->getLeft()); cout << *(treeNode->getInfo())<<" "; inorder(treeNode->getRight()); } }

Traversing a Binary Tree


void postorder(TreeNode<int>* treeNode) { if( treeNode != NULL ) { postorder(treeNode->getLeft()); postorder(treeNode->getRight()); cout << *(treeNode->getInfo())<<" "; } }

Traversing a Binary Tree


cout << "inorder: "; preorder( root); cout << "inorder: "; inorder( root ); cout << "postorder: "; postorder( root );

Traversing a Binary Tree


14 4 15

3 7 5

9 16

18 20 17

Preorder: 14 4 3 9 7 5 15 18 16 17 20

Traversing a Binary Tree


14 4 15

3 7 5

9 16

18 20 17

Inorder: 3 4 5 7 9 14 15 16 17 18 20

Traversing a Binary Tree


14 4 15

3 7 5

9 16

18 20 17

Postorder:

3 5 7 9 4 17 16 20 18 15 14

Recursive Call
Recall that a stack is used during function calls. The caller function places the arguments on the stack and passes control to the called function. Local variables are allocated storage on the call stack. Calling a function itself makes no difference as far as the call stack is concerned.

Stack Layout during a call


Here is stack layout when function F calls function F (recursively):
Parameters(F) Local variables(F) Return address(F) Parameters(F) sp Parameters(F) Local variables(F) Return address(F) sp Parameters(F) Local variables(F) Parameters(F) Local variables(F) Return address(F)

sp
At point of call

Return address(F) During execution of F After call

Recursive Call
Recall that a stack is used during function calls. The caller function places the arguments on the stack and passes control to the called function. Local variables are allocated storage on the call stack. Calling a function itself makes no difference as far as the call stack is concerned.

Stack Layout during a call


Here is stack layout when function F calls function F (recursively):
Parameters(F) Local variables(F) Return address(F) Parameters(F) sp Parameters(F) Local variables(F) Return address(F) sp Parameters(F) Local variables(F) Parameters(F) Local variables(F) Return address(F)

sp
At point of call

Return address(F) During execution of F After call

Recursion: preorder
14 4 15
preorder(14) 14 ..preorder(4) 4 ....preorder(3) 3 ......preorder(null) ......preorder(null) ....preorder(9) 9 ......preorder(7) 7 ........preorder(5) 5 ..........preorder(null) ..........preorder(null) ........preorder(null) ......preorder(null)

3
7 5

9
16

18 20 17

Recursion: preorder
14 4 15
..preorder(15) 15 ....preorder(null) ....preorder(18) 18 ......preorder(16) 16 ........preorder(null) ........preorder(17) 17 ..........preorder(null) ..........preorder(null) ......preorder(20) 20 ........preorder(null) ........preorder(null)

3
7 5

9
16

18 20 17

Recursion: inorder
14 4 15
inorder(14) ..inorder(4) ....inorder(3) ......inorder(null) 3 ......inorder(null) 4 ....inorder(9) ......inorder(7) ........inorder(5) ..........inorder(null) 5 ..........inorder(null) 7 ........inorder(null) 9 ......inorder(null) 14

3
7 5

9
16

18 20 17

Recursion: inorder
14 4 15
..inorder(15) ....inorder(null) 15 ....inorder(18) ......inorder(16) ........inorder(null) 16 ........inorder(17) ..........inorder(null) 17 ..........inorder(null) 18 ......inorder(20) ........inorder(null) 20 ........inorder(null)

3
7 5

9
16

18 20 17

Non Recursive Traversal


We can implement non-recursive versions of the preorder, inorder and postorder traversal by using an explicit stack. The stack will be used to store the tree nodes in the appropriate order. Here, for example, is the routine for inorder traversal that uses a stack.

Non Recursive Traversal


void inorder(TreeNode<int>* root) { Stack<TreeNode<int>* > stack; TreeNode<int>* p; p = root; do { while( p != NULL ) { stack.push( p ); p = p->getLeft(); } // at this point, left tree is empty

Non Recursive Traversal


void inorder(TreeNode<int>* root) { Stack<TreeNode<int>* > stack; TreeNode<int>* p; p = root; do { while( p != NULL ) { stack.push( p ); p = p->getLeft(); } // at this point, left tree is empty

Non Recursive Traversal


void inorder(TreeNode<int>* root) { Stack<TreeNode<int>* > stack; TreeNode<int>* p; p = root; do { while( p != NULL ) { stack.push( p ); p = p->getLeft(); } // at this point, left tree is empty

Non Recursive Traversal

if( !stack.empty() ) { p = stack.pop(); cout << *(p->getInfo()) << " "; // go back & traverse right subtree p = p->getRight(); } } while ( !stack.empty() || p != NULL ); }

Non Recursive Traversal

if( !stack.empty() ) { p = stack.pop(); cout << *(p->getInfo()) << " "; // go back & traverse right subtree p = p->getRight(); } } while ( !stack.empty() || p != NULL ); }

Non Recursive Traversal


if( !stack.empty() ) { p = stack.pop(); cout << *(p->getInfo()) << " "; // go back & traverse right subtree p = p->getRight(); } } while ( !stack.empty() || p != NULL ); }

Non Recursive Traversal


if( !stack.empty() ) { p = stack.pop(); cout << *(p->getInfo()) << " "; // go back & traverse right subtree p = p->getRight(); } } while ( !stack.empty() || p != NULL ); }

Nonrecursive Inorder
14 4 15
push(14) ..push(4) ....push(3) 3 4 ..push(9) ....push(7) ......push(5) 5 7 9 14 push(15) 15 push(18) ..push(16) 16 ..push(17) 17 18 push(20) 20

3
7 5

9
16

18 20 17

Traversal Trace
recursive inorder

inorder(14) ..inorder(4) ....inorder(3) 3 4 ..inorder(9) ....inorder(7) ......inorder(5) 5 7 9 14 inorder(15) 15 inorder(18) ..inorder(16) 16 ..inorder(17) 17 18 inorder(20) 20

nonrecursive inorder
push(14) ..push(4) ....push(3) 3 4 ..push(9) ....push(7) ......push(5) 5 7 9 14 push(15) 15 push(18) ..push(16) 16 ..push(17) 17 18 push(20) 20

Traversal Trace
recursive inorder
inorder(14) ..inorder(4) ....inorder(3) 3 4 ..inorder(9) ....inorder(7) ......inorder(5) 5 7 9 14 inorder(15) 15 inorder(18) ..inorder(16) 16 ..inorder(17) 17 18 inorder(20) 20

nonrecursive inorder
push(14) ..push(4) ....push(3) 3 4 ..push(9) ....push(7) ......push(5) 5 7 9 14 push(15) 15 push(18) ..push(16) 16 ..push(17) 17 18 push(20) 20

Traversal Trace
recursive inorder
inorder(14) ..inorder(4) ....inorder(3) 3 4 ..inorder(9) ....inorder(7) ......inorder(5) 5 7 9 14 inorder(15) 15 inorder(18) ..inorder(16) 16 ..inorder(17) 17 18 inorder(20) 20

nonrecursive inorder
push(14) ..push(4) ....push(3) 3 4 ..push(9) ....push(7) ......push(5) 5 7 9 14 push(15) 15 push(18) ..push(16) 16 ..push(17) 17 18 push(20) 20

Traversal Trace
recursive inorder
inorder(14) ..inorder(4) ....inorder(3) 3 4 ..inorder(9) ....inorder(7) ......inorder(5) 5 7 9 14 inorder(15) 15 inorder(18) ..inorder(16) 16 ..inorder(17) 17 18 inorder(20) 20

nonrecursive inorder
push(14) ..push(4) ....push(3) 3 4 ..push(9) ....push(7) ......push(5) 5 7 9 14 push(15) 15 push(18) ..push(16) 16 ..push(17) 17 18 push(20) 20

Level-order Traversal
There is yet another way of traversing a binary tree that is not related to recursive traversal procedures discussed previously. In level-order traversal, we visit the nodes at each level before proceeding to the next level. At each level, we visit the nodes in a leftto-right order.

Level-order Traversal
14 4 15

3 7 5

9 16

18 20 17

Level-order:

14 4 15 3 9 18 7 16 20 5 17

Level-order Traversal
There is yet another way of traversing a binary tree that is not related to recursive traversal procedures discussed previously. In level-order traversal, we visit the nodes at each level before proceeding to the next level. At each level, we visit the nodes in a leftto-right order.

Level-order Traversal
14 4 15

3 7 5

9 16

18 20 17

Level-order:

14 4 15 3 9 18 7 16 20 5 17

Level-order Traversal
How do we do level-order traversal? Surprisingly, if we use a queue instead of a stack, we can visit the nodes in levelorder. Here is the code for level-order traversal:

Level-order Traversal
void levelorder(TreeNode<int>* treeNode)
{ Queue<TreeNode<int>* > q; if( treeNode == NULL ) return; q.enqueue( treeNode); while( !q.empty() ) { treeNode = q.dequeue(); cout << *(treeNode->getInfo()) << " "; if(treeNode->getLeft() != NULL ) q.enqueue( treeNode->getLeft()); if(treeNode->getRight() != NULL ) q.enqueue( treeNode->getRight()); } cout << endl; }

Level-order Traversal
void levelorder(TreeNode<int>* treeNode) { Queue<TreeNode<int>* > q; if( treeNode == NULL ) return; q.enqueue( treeNode); while( !q.empty() ) { treeNode = q.dequeue(); cout << *(treeNode->getInfo()) << " "; if(treeNode->getLeft() != NULL ) q.enqueue( treeNode->getLeft()); if(treeNode->getRight() != NULL ) q.enqueue( treeNode->getRight()); } cout << endl; }

Level-order Traversal
void levelorder(TreeNode<int>* treeNode) { Queue<TreeNode<int>* > q; if( treeNode == NULL ) return; q.enqueue( treeNode); while( !q.empty() ) { treeNode = q.dequeue(); cout << *(treeNode->getInfo()) << " "; if(treeNode->getLeft() != NULL ) q.enqueue( treeNode->getLeft()); if(treeNode->getRight() != NULL ) q.enqueue( treeNode->getRight()); } cout << endl; }

Level-order Traversal
void levelorder(TreeNode<int>* treeNode) { Queue<TreeNode<int>* > q; if( treeNode == NULL ) return; q.enqueue( treeNode); while( !q.empty() ) { treeNode = q.dequeue(); cout << *(treeNode->getInfo()) << " "; if(treeNode->getLeft() != NULL ) q.enqueue( treeNode->getLeft()); if(treeNode->getRight() != NULL ) q.enqueue( treeNode->getRight()); } cout << endl; }

Level-order Traversal
void levelorder(TreeNode<int>* treeNode) { Queue<TreeNode<int>* > q; if( treeNode == NULL ) return; q.enqueue( treeNode); while( !q.empty() ) { treeNode = q.dequeue(); cout << *(treeNode->getInfo()) << " "; if(treeNode->getLeft() != NULL ) q.enqueue( treeNode->getLeft()); if(treeNode->getRight() != NULL ) q.enqueue( treeNode->getRight()); } cout << endl; }

Level-order Traversal
void levelorder(TreeNode<int>* treeNode) { Queue<TreeNode<int>* > q; if( treeNode == NULL ) return; q.enqueue( treeNode); while( !q.empty() ) { treeNode = q.dequeue(); cout << *(treeNode->getInfo()) << " "; if(treeNode->getLeft() != NULL ) q.enqueue( treeNode->getLeft()); if(treeNode->getRight() != NULL ) q.enqueue( treeNode->getRight()); } cout << endl; }

Level-order Traversal
void levelorder(TreeNode<int>* treeNode) { Queue<TreeNode<int>* > q; if( treeNode == NULL ) return; q.enqueue( treeNode); while( !q.empty() ) { treeNode = q.dequeue(); cout << *(treeNode->getInfo()) << " "; if(treeNode->getLeft() != NULL ) q.enqueue( treeNode->getLeft()); if(treeNode->getRight() != NULL ) q.enqueue( treeNode->getRight()); } cout << endl; }

Level-order Traversal
void levelorder(TreeNode<int>* treeNode) { Queue<TreeNode<int>* > q; if( treeNode == NULL ) return; q.enqueue( treeNode); while( !q.empty() ) { treeNode = q.dequeue(); cout << *(treeNode->getInfo()) << " "; if(treeNode->getLeft() != NULL ) q.enqueue( treeNode->getLeft()); if(treeNode->getRight() != NULL ) q.enqueue( treeNode->getRight()); } cout << endl; }

Level-order Traversal
14 4 3 7 5 9 16 17 15 18 20

Queue: 14 Output:

Level-order Traversal
14 4 3 7 5 9 16 17 15 18 20

Queue: 4 15 Output: 14

Level-order Traversal
14 4 3 7 5 9 16 17 15 18 20

Queue: 15 3 9 Output: 14 4

Level-order Traversal
14 4 3 7 5 9 16 17 15 18 20

Queue: 3 9 18 Output: 14 4 15

Level-order Traversal
14 4 3 7 5 9 16 17 15 18 20

Queue: 9 18 Output: 14 4 15 3

Level-order Traversal
14 4 3 7 5 9 16 17 15 18 20

Queue: 18 7 Output: 14 4 15 3 9

Level-order Traversal
14 4 3 7 5 9 16 17 15 18 20

Queue: 7 16 20 Output: 14 4 15 3 9 18

Level-order Traversal
14 4 3 7 5 9 16 17 15 18 20

Queue: 16 20 5 Output: 14 4 15 3 9 18 7

Level-order Traversal
14 4 3 7 5 9 16 17 15 18 20

Queue: 20 5 17 Output: 14 4 15 3 9 18 7 16

Level-order Traversal
14 4 3 7 5 9 16 17 15 18 20

Queue: 5 17 Output: 14 4 15 3 9 18 7 16 20

Level-order Traversal
14 4 3 7 5 9 16 17 15 18 20

Queue: 17 Output: 14 4 15 3 9 18 7 16 20 5

Level-order Traversal
14 4 3 7 5 9 16 17 15 18 20

Queue: Output: 14 4 15 3 9 18 7 16 20 5 17

Storing other Type of Data


The examples of binary trees so far have been storing integer data in the tree node. This is surely not a requirement. Any type of data can be stored in a tree node. Here, for example, is the C++ code to build a tree with character strings.

Binary Search Tree with Strings


void wordTree() { TreeNode<char>* root = new TreeNode<char>(); static char* word[] = "babble", "fable", "jacket", "backup", "eagle","daily","gain","bandit","abandon", "abash","accuse","economy","adhere","advise","cease", "debunk","feeder","genius","fetch","chain", NULL}; root->setInfo( word[0] ); for(i=1; word[i]; i++ ) insert(root, word[i] ); inorder( root ); cout << endl; }

Binary Search Tree with Strings


void wordTree() { TreeNode<char>* root = new TreeNode<char>(); static char* word[] = "babble", "fable", "jacket", "backup", "eagle","daily","gain","bandit","abandon", "abash","accuse","economy","adhere","advise","cease", "debunk","feeder","genius","fetch","chain", NULL}; root->setInfo( word[0] ); for(i=1; word[i]; i++ ) insert(root, word[i] ); inorder( root ); cout << endl; }

Binary Search Tree with Strings


void wordTree() { TreeNode<char>* root = new TreeNode<char>(); static char* word[] = "babble", "fable", "jacket", "backup", "eagle","daily","gain","bandit","abandon", "abash","accuse","economy","adhere","advise","cease", "debunk","feeder","genius","fetch","chain", NULL}; root->setInfo( word[0] ); for(i=1; word[i]; i++ ) insert(root, word[i] ); inorder( root ); cout << endl; }

Binary Search Tree with Strings


void wordTree() { TreeNode<char>* root = new TreeNode<char>(); static char* word[] = "babble", "fable", "jacket", "backup", "eagle","daily","gain","bandit","abandon", "abash","accuse","economy","adhere","advise","cease", "debunk","feeder","genius","fetch","chain", NULL}; root->setInfo( word[0] );

for(i=1; word[i]; i++ ) insert(root, word[i] ); inorder( root ); cout << endl; }

Binary Search Tree with Strings


void wordTree() { TreeNode<char>* root = new TreeNode<char>(); static char* word[] = "babble", "fable", "jacket", "backup", "eagle","daily","gain","bandit","abandon", "abash","accuse","economy","adhere","advise","cease", "debunk","feeder","genius","fetch","chain", NULL}; root->setInfo( word[0] ); for(i=1; word[i]; i++ ) insert(root, word[i] ); inorder( root ); cout << endl; }

Binary Search Tree with Strings


void insert(TreeNode<char>* root, char* info)
{ TreeNode<char>* node = new TreeNode<char>(info); TreeNode<char> *p, *q; p = q = root; while( strcmp(info, p->getInfo()) != 0 && q != NULL ) { p = q; if( strcmp(info, p->getInfo()) < 0 ) q = p->getLeft(); else q = p->getRight(); }

Binary Search Tree with Strings


void insert(TreeNode<char>* root, char* info) { TreeNode<char>* node = new TreeNode<char>(info); TreeNode<char> *p, *q; p = q = root; while( strcmp(info, p->getInfo()) != 0 && q != NULL ) { p = q; if( strcmp(info, p->getInfo()) < 0 ) q = p->getLeft(); else q = p->getRight(); }

Binary Search Tree with Strings


void insert(TreeNode<char>* root, char* info) { TreeNode<char>* node = new TreeNode<char>(info); TreeNode<char> *p, *q; p = q = root; while( strcmp(info, p->getInfo()) != 0 && q != NULL ) { p = q; if( strcmp(info, p->getInfo()) < 0 ) q = p->getLeft(); else q = p->getRight(); }

Binary Search Tree with Strings


void insert(TreeNode<char>* root, char* info) { TreeNode<char>* node = new TreeNode<char>(info); TreeNode<char> *p, *q; p = q = root; while( strcmp(info, p->getInfo()) != 0 && q != NULL ) { p = q; if( strcmp(info, p->getInfo()) < 0 ) q = p->getLeft(); else q = p->getRight(); }

Binary Search Tree with Strings


void insert(TreeNode<char>* root, char* info) { TreeNode<char>* node = new TreeNode<char>(info); TreeNode<char> *p, *q; p = q = root; while( strcmp(info, p->getInfo()) != 0 && q != NULL ) { p = q; if( strcmp(info, p->getInfo()) < 0 ) q = p->getLeft(); else q = p->getRight(); }

Binary Search Tree with Strings

if( strcmp(info, p->getInfo()) == 0 ){ cout << "attempt to insert duplicate: " << *info << endl; delete node; } else if( strcmp(info, p->getInfo()) < 0 ) p->setLeft( node ); else p->setRight( node ); }

Binary Search Tree with Strings


if( strcmp(info, p->getInfo()) == 0 ){ cout << "attempt to insert duplicate: " << *info << endl; delete node; } else if( strcmp(info, p->getInfo()) < 0 ) p->setLeft( node ); else p->setRight( node ); }

Binary Search Tree with Strings


if( strcmp(info, p->getInfo()) == 0 ){ cout << "attempt to insert duplicate: " << *info << endl; delete node; } else if( strcmp(info, p->getInfo()) < 0 ) p->setLeft( node ); else p->setRight( node ); }

Binary Search Tree with Strings


Output:
abandon abash accuse adhere advise babble backup bandit cease chain daily debunk eagle economy fable feeder fetch gain genius jacket

Binary Search Tree with Strings


abandon abash accuse adhere advise babble backup bandit cease chain daily debunk eagle economy fable feeder fetch gain genius jacket Notice that the words are sorted in increasing order when we traversed the tree in inorder manner.

Binary Search Tree with Strings


abandon abash accuse adhere advise babble backup bandit cease chain daily debunk eagle economy fable feeder fetch gain genius jacket Notice that the words are sorted in increasing order when we traversed the tree in inorder manner. This should not come as a surprise if you consider how we built the BST.

Binary Search Tree with Strings


abandon abash accuse adhere advise babble backup bandit cease chain daily debunk eagle economy fable feeder fetch gain genius jacket Notice that the words are sorted in increasing order when we traversed the tree in inorder manner. This should not come as a surprise if you consider how we built the BST. For a given node, values less than the info in the node were all in the left subtree and values greater or equal were in the right.

Binary Search Tree with Strings


abandon abash accuse adhere advise babble backup bandit cease chain daily debunk eagle economy fable feeder fetch gain genius jacket Notice that the words are sorted in increasing order when we traversed the tree in inorder manner. This should not come as a surprise if you consider how we built the BST. For a given node, values less than the info in the node were all in the left subtree and values greater or equal were in the right. Inorder prints the left subtree, then the node finally the right subtree.

Binary Search Tree with Strings


abandon abash accuse adhere advise babble backup bandit cease chain daily debunk eagle economy fable feeder fetch gain genius jacket Notice that the words are sorted in increasing order when we traversed the tree in inorder manner. This should not come as a surprise if you consider how we built the BST. For a given node, values less than the info in the node were all in the left subtree and values greater or equal were in the right. Inorder prints the left subtree, then the node finally the right subtree. Building a BST and doing an inorder traversal leads to a sorting algorithm.

Binary Search Tree with Strings


abandon abash accuse adhere advise babble backup bandit cease chain daily debunk eagle economy fable feeder fetch gain genius jacket Notice that the words are sorted in increasing order when we traversed the tree in inorder manner. This should not come as a surprise if you consider how we built the BST. For a given node, values less than the info in the node were all in the left subtree and values greater or equal were in the right. Inorder prints the left subtree, then the node finally the right subtree. Building a BST and doing an inorder traversal leads to a sorting algorithm.

Deleting a node in BST


As is common with many data structures, the hardest operation is deletion. Once we have found the node to be deleted, we need to consider several possibilities. If the node is a leaf, it can be deleted immediately.

Deleting a node in BST


If the node has one child, the node can be deleted after its parent adjusts a pointer to bypass the node and connect to inorder successor.
6 2 1 3 4 8

Deleting a node in BST


The inorder traversal order has to be maintained after the delete.
6 2 1 3 4 8 1 3

6 2 4 8

Deleting a node in BST


The inorder traversal order has to be maintained after the delete.
6 2 1 3 4 8 1 3

6 2 4 8 1

6 2 3 8

Deleting a node in BST


The complicated case is when the node to be deleted has both left and right subtrees. The strategy is to replace the data of this node with the smallest data of the right subtree and recursively delete that node.

Deleting a node in BST


Delete(2): locate inorder successor
6 2 1 3 4
Inorder successor

8 5

Deleting a node in BST


Delete(2): locate inorder successor
6 2 1 3 4
Inorder successor

Inorder successor will be the left-most node in the right subtree of 2. 8 The inorder successor will not have a left child because if it did, that child would be the left-most node.

Deleting a node in BST


Delete(2): copy data from inorder successor
6 2 1 3 4 5 8 1 3 4

6 3 5 8

Deleting a node in BST


Delete(2): remove the inorder successor
6 2 1 3 4 5 8 1 3 4

6 3 5 8 1

6 3 5 3 4 8

Deleting a node in BST


Delete(2)

6 3 8 5 3 4

6 3 8 5 4

Deleting a node in BST


As is common with many data structures, the hardest operation is deletion. Once we have found the node to be deleted, we need to consider several possibilities. If the node is a leaf, it can be deleted immediately.

Deleting a node in BST


If the node has one child, the node can be deleted after its parent adjusts a pointer to bypass the node and connect to inorder successor.
6 2 1 3 4 8

Deleting a node in BST


The inorder traversal order has to be maintained after the delete.
6 2 1 3 4 8 1 3

6 2 4 8

Deleting a node in BST


The inorder traversal order has to be maintained after the delete.
6 2 1 3 4 8 1 3

6 2 4 8 1

6 2 3 8

Deleting a node in BST


The complicated case is when the node to be deleted has both left and right subtrees. The strategy is to replace the data of this node with the smallest data of the right subtree and recursively delete that node.

Deleting a node in BST


Delete(2): locate inorder successor
6 2 1 3 4
Inorder successor

8 5

Deleting a node in BST


Delete(2): locate inorder successor
6 2 1 3 4
Inorder successor

Inorder successor will be the left-most node in the right subtree of 2. 8 The inorder successor will not have a left child because if it did, that child would be the left-most node.

Deleting a node in BST


Delete(2): copy data from inorder successor
6 2 1 3 4 5 8 1 3 4

6 3 5 8

Deleting a node in BST


Delete(2): remove the inorder successor
6 2 1 3 4 5 8 1 3 4

6 3 5 8 1

6 3 5 3 4 8

Deleting a node in BST


Delete(2)

6 3 8 5 3 4

6 3 8 5 4

C++ code for delete


delete is C++ keyword. We will call our deleteNode routine remove. Here is the C++ code for remove.

C++ code for delete

TreeNode<int>* remove(TreeNode<int>* tree, int info) { TreeNode<int>* t; int cmp = info - *(tree->getInfo()); if( cmp < 0 ){ t = remove(tree->getLeft(), info); tree->setLeft( t ); } else if( cmp > 0 ){ t = remove(tree->getRight(), info); tree->setRight( t ); }

C++ code for delete


TreeNode<int>* remove(TreeNode<int>* tree, int info) { TreeNode<int>* t; int cmp = info - *(tree->getInfo()); if( cmp < 0 ){ t = remove(tree->getLeft(), info); tree->setLeft( t ); } else if( cmp > 0 ){ t = remove(tree->getRight(), info); tree->setRight( t ); }

C++ code for delete


TreeNode<int>* remove(TreeNode<int>* tree, int info) { TreeNode<int>* t; int cmp = info - *(tree->getInfo()); if( cmp < 0 ){ t = remove(tree->getLeft(), info); tree->setLeft( t ); } else if( cmp > 0 ){ t = remove(tree->getRight(), info); tree->setRight( t ); }

C++ code for delete


TreeNode<int>* remove(TreeNode<int>* tree, int info) { TreeNode<int>* t; int cmp = info - *(tree->getInfo()); if( cmp < 0 ){ t = remove(tree->getLeft(), info); tree->setLeft( t ); } else if( cmp > 0 ){ t = remove(tree->getRight(), info); tree->setRight( t ); }

C++ code for delete


//two children, replace with inorder successor

else if(tree->getLeft() != NULL


&& tree->getRight() != NULL ){ TreeNode<int>* minNode; minNode = findMin(tree->getRight()); tree->setInfo( minNode->getInfo() ); t = remove(tree->getRight(), *(minNode->getInfo())); tree->setRight( t ); }

C++ code for delete


//two children, replace with inorder successor

else if(tree->getLeft() != NULL


&& tree->getRight() != NULL ){ TreeNode<int>* minNode; minNode = findMin(tree->getRight()); tree->setInfo( minNode->getInfo() ); t = remove(tree->getRight(), *(minNode->getInfo())); tree->setRight( t ); }

C++ code for delete


//two children, replace with inorder successor

else if(tree->getLeft() != NULL


&& tree->getRight() != NULL ){ TreeNode<int>* minNode; minNode = findMin(tree->getRight()); tree->setInfo( minNode->getInfo() ); t = remove(tree->getRight(), *(minNode->getInfo())); tree->setRight( t ); }

C++ code for delete


//two children, replace with inorder successor

else if(tree->getLeft() != NULL


&& tree->getRight() != NULL ){ TreeNode<int>* minNode; minNode = findMin(tree->getRight()); tree->setInfo( minNode->getInfo() ); t = remove(tree->getRight(), *(minNode->getInfo())); tree->setRight( t ); }

C++ code for delete


//two children, replace with inorder successor

else if(tree->getLeft() != NULL


&& tree->getRight() != NULL ){ TreeNode<int>* minNode; minNode = findMin(tree->getRight()); tree->setInfo( minNode->getInfo() ); t = remove(tree->getRight(), *(minNode->getInfo())); } tree->setRight( t );

C++ code for delete


else { // case 1
//will
handle 0 children

TreeNode<int>* nodeToDelete = tree;


if( tree->getLeft() == NULL ) tree = tree->getRight(); else if( tree->getRight() == NULL ) tree = tree->getLeft(); else tree = NULL; delete nodeToDelete; } return tree; }

C++ code for delete


else { // case 1
//will
handle 0 children

TreeNode<int>* nodeToDelete = tree;


if( tree->getLeft() == NULL ) tree = tree->getRight(); else if( tree->getRight() == NULL ) tree = tree->getLeft(); else tree = NULL; delete nodeToDelete; } return tree; }

C++ code for delete


else { // case 1
//will
handle 0 children

TreeNode<int>* nodeToDelete = tree;


if( tree->getLeft() == NULL ) tree = tree->getRight(); else if( tree->getRight() == NULL ) tree = tree->getLeft(); else tree = NULL; } return tree; } delete nodeToDelete;

C++ code for delete

TreeNode<int>* findMin(TreeNode<int>* tree)

{
if( tree == NULL ) return NULL;

if( tree->getLeft() == NULL )


return tree; // this is it. return findMin( tree->getLeft() );

C++ code for delete


TreeNode<int>* findMin(TreeNode<int>* tree)

if( tree == NULL ) return NULL;

if( tree->getLeft() == NULL )


return tree; // this is it. return findMin( tree->getLeft() );

C++ code for delete


TreeNode<int>* findMin(TreeNode<int>* tree)

{
if( tree == NULL ) return NULL;

if( tree->getLeft() == NULL )


return tree; // this is it.

return findMin( tree->getLeft() );

BinarySearchTree.h
Let us design the BinarySearchTree class (factory).

BinarySearchTree.h
#ifndef _BINARY_SEARCH_TREE_H_

#define _BINARY_SEARCH_TREE_H_
#include <iostream.h> // For NULL

// Binary node and forward declaration template <class EType> class BinarySearchTree;

BinarySearchTree.h
#ifndef _BINARY_SEARCH_TREE_H_

#define _BINARY_SEARCH_TREE_H_
#include <iostream.h> // For NULL

// Binary node and forward declaration template <class EType> class BinarySearchTree;

BinarySearchTree.h
template <class EType> class BinaryNode { EType element; BinaryNode *left; BinaryNode *right; BinaryNode( const EType & theElement, BinaryNode *lt, BinaryNode *rt ) : element( theElement ), left( lt ), right( rt ) { } friend class BinarySearchTree<EType>; };

BinarySearchTree.h
template <class EType> class BinaryNode { EType element; BinaryNode *left; BinaryNode *right; BinaryNode( const EType & theElement, BinaryNode *lt, BinaryNode *rt ) : element( theElement ), left( lt ), right( rt ) { } friend class BinarySearchTree<EType>; };

BinarySearchTree.h
template <class EType> class BinaryNode { EType element; BinaryNode *left; BinaryNode *right;

BinaryNode( const EType & theElement, BinaryNode *lt, BinaryNode *rt ) : element( theElement ), left( lt ), right( rt ) { } friend class BinarySearchTree<EType>; };

BinarySearchTree.h
template <class EType> class BinaryNode { EType element; BinaryNode *left; BinaryNode *right; BinaryNode( const EType & theElement, BinaryNode *lt, BinaryNode *rt ) : element( theElement ), left( lt ), right( rt ) { } friend class BinarySearchTree<EType>; };

BinarySearchTree.h
template <class EType> class BinarySearchTree { public: BinarySearchTree( const EType& notFound ); BinarySearchTree( const BinarySearchTree& rhs ); ~BinarySearchTree( ); const EType& findMin( ) const; const EType& findMax( ) const; const EType& find( const EType & x ) const; bool isEmpty( ) const; void printInorder( ) const;

BinarySearchTree.h
void insert( const EType& x ); void remove( const EType& x ); const BinarySearchTree & operator= ( const BinarySearchTree & rhs );

BinarySearchTree.h
private: BinaryNode<EType>* root; // ITEM_NOT_FOUND object used to signal failed finds const EType ITEM_NOT_FOUND; const EType& elementAt( BinaryNode<EType>* t ); void insert(const EType& x, BinaryNode<EType>* & t); void remove(const EType& x, BinaryNode<EType>* & t); BinaryNode<EType>* findMin(BinaryNode<EType>* t); BinaryNode<EType>* findMax(BinaryNode<EType>* t); BinaryNode<EType>* find(const EType& x, BinaryNode<EType>* t ); void makeEmpty(BinaryNode<EType>* & t); void printInorder(BinaryNode<EType>* t); }; #endif

Potrebbero piacerti anche