1 / 61

# Trees More Tables - PowerPoint PPT Presentation

Trees & More Tables. (Walls & Mirrors - Chapter 10 & Beginning of 11). Overview. Terminology Binary Trees Pointer-Based Representation of a Binary Tree Array-Based Representation of a Binary Tree Traversing a Binary Tree Binary Search Tree Implementation of a Table Treesort. Terminology.

Related searches for Trees More Tables

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

## PowerPoint Slideshow about 'Trees More Tables' - patricia

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

### Trees & More Tables

(Walls & Mirrors - Chapter 10 & Beginning of 11)

• Terminology

• Binary Trees

• Pointer-Based Representation of a Binary Tree

• Array-Based Representation of a Binary Tree

• Traversing a Binary Tree

• Binary Search Tree Implementation of a Table

• Treesort

• A tree is a collection of nodes and directed edges, satisfying the following properties:

• There is one specially designated node called the root, which has no edges pointing to it.

• Every node except the root has exactly one edge pointing to it.

• There is a unique path (of nodes and edges) from the root to each node.

root

edge

node

Graphical Representation

• Trees, as defined on the preceding slide, are typically drawn with circles (or rectangles) representing the nodes and arrows representing the edges.

• The root is typically placed at the top of the diagram, with the rest of the tree below it.

• If an edge goes from node a to node b, then a is called the parent of b, and b is called a child of a.

• Children of the same parent are called siblings.

• If there is a path from a to b, then a is called an ancestor of b, and b is called a descendent of a.

• A node with all of its descendants is called a subtree.

• If a node has no children, then it is called a leaf of the tree.

• If a node has no parent (there will be exactly one of these), then it is the root of the tree.

B

C

F

D

E

G

H

I

J

K

Terminology: Example

• A is the root

• D, E, G, H, J & K are leaves

• B is the parent of D, E & F

• D, E & F are siblings and children of B

• I, J & K are descendants of B

• A & B are ancestors of I

subtree

trees are distinct.)

Binary Trees

• Intuitively, a binary tree is LIKE a tree in which each node has no more than two children.

• Formally, a binary tree is a set T of nodes such that either:

• T is empty, or

• T consists of a single node, r, called the root, and two (non-overlapping) binary trees, called the left and rightsubtrees of r.

• UNLIKE trees, binary trees may be empty, and they distinguish between left and rightsubtrees.

John

3

34

Brenda

Peter

55

2

8

Amy

Mary

Tom

5

13

Binary Search Trees

• A binary search tree is a binary tree in which each node, n, has a value satisfying the following properties:

• n’s value is > all values in its left subtree, TL,

• n’s value is < all values in its right subtree, TR, and

• TLand TRare both binary search trees.

• Intuitively, the level of a node is the number of nodes on a path from the root to the node.

• Formally, level of node, n:

• If n is the root of a tree, then it is at level 1.

• Otherwise, its level is 1 greater than the level of its parent.

• Height of binary tree, T:

• If T is empty, its height is 0.

• Otherwise, its height is the maximum level of its nodes, or, equivalently, 1 greater than the height of the root’s taller subtree. Namely,

height(T) = 1 + max { height( TL ), height(TR ) }

• Intuitively, a binary tree is full if it has no missing nodes.

• Formally, a binary tree of height h is fullif

• It is empty (h = 0).

• Otherwise, the root’s subtrees are full binary trees of height h – 1.

• If not empty, each node has2 children, except the nodes at level h which have no children.

• Alternatively, the binary tree has all of its leaves at level h.

• Intuitively, a binary tree of height h is complete if it is full down to level h – 1, and level h is filled from left to right.

• Formally, a binary tree of height h is complete if

• All nodes at level h – 2 and above have 2 children each,

• If a node at level h – 1 has children, all nodes to its left at the same level have 2 children each, and

• If a node at level h – 1 has 1 child, it is a left child.

• A binary tree is balanced if the difference in height between any node’s left and right subtree is  1.

• Note that:

• A full binary tree is also complete.

• A complete binary tree is not always full.

• Full and complete binary trees are also balanced.

• Balanced binary trees are not always full or complete.

Binary Tree: Pointer-Based Representation

struct TreeNode; // Binary Tree nodes are struct’s

typedef string TreeItemType; // items in TreeNodes are string’s

class BinaryTree

{

public:

// declarations of public member functions

private:

TreeNode *root; // pointer to root of Binary Tree

};

struct TreeNode // node in a Binary Tree:

{ // place in Implementation file

TreeItemType item;

TreeNode *leftChild; // pointer to TreeNode’s left child

TreeNode *rightChild; // pointer to TreeNode’s right child

};

Binary Tree: Array-Based Representation

Basic Idea:

• Instead of using pointers to the left and right child of a node, use indices into the array of nodes representing the binary tree.

• Also, use variable free as an index to the first position in the array that is available for a new entry. Use either the left or right child indices to indicate additional, available positions.

• Together, the list of available positions in the array is called the free list.

0

free

6

Nancy

Ellen

Alan

Tom

Jane

Bob

Binary Tree: Array-Based Representation

0

free

7

Nancy

Mary

Ellen

Alan

Tom

Jane

Bob

Binary Tree: Array-Based Representation

0

free

4

Nancy

Mary

Alan

Tom

Jane

Bob

Binary Tree: Array-Based Representation

• Ellen deleted.

Binary Tree: Array-Based Representation

const int MaxNodes = 100; // maximum size of a Binary Tree

typedef string TreeItemType; // items in TreeNodes are string’s

struct TreeNode // node in a Binary Tree

{

TreeItemType item;

int leftChild; // index of TreeNode’s left child

int rightChild; // index of TreeNode’s right child

};

class BinaryTree

{

public:

// declarations of public member functions

private:

TreeNode node[MaxNodes];

int root; // index of root of Binary Tree

int free; // index of free list, linked by rightChild

};

• Preorder

• Inorder

• Postorder

Preorder Traversal of a Binary Tree

Basic Idea:

1) Visit the root.

2) Recursively invoke preorder on the left subtree.

3) Recursively invoke preorder on the right subtree.

7

2

3

4

5

6

60

40

10

70

20

30

50

Preorder Traversal of a Binary Tree

Preorder Result: 60, 20, 10, 40, 30, 50, 70

Inorder Traversal of a Binary Tree

Basic Idea:

1) Recursively invoke inorder on the left subtree.

2) Visit the root.

3) Recursively invoke inorder on the right subtree.

7

2

1

4

3

5

60

40

10

70

20

30

50

Inorder Traversal of a Binary Tree

Inorder Result: 10, 20, 30, 40, 50, 60, 70

Postorder Traversal of a Binary Tree

Basic Idea:

1) Recursively invoke postorder on the left subtree.

2) Recursively invoke postorder on the right subtree.

3) Visit the root.

6

5

1

4

2

3

60

40

10

70

20

30

50

Postorder Traversal of a Binary Tree

Postorder Result: 10, 30, 50, 40, 20, 70, 60

Pointer-Based, Preorder Traversal in C++

// FunctionTypeis a pointer to a function with argument

// (TreeItemType &) that returns void.

typedef void (*FunctionType) (TreeItemType &treeItem);

// Public member function

void BinaryTree::preorderTraverse( FunctionType visit )

{

preorder( root, visit );

}

Pointer-Based, Preorder Traversal in C++

// Private member function

void BinaryTree::preorder( TreeNode *treePtr, FunctionType visit )

{

if( treePtr != NULL )

{

visit( treePtr -> item );

preorder( treePtr -> leftChild, visit );

preorder( treePtr -> rightChild, visit );

}

}

Pointer-Based, Preorder Traversal in C++

Suppose that we define the function

void printItem( TreeItemType &treeItem )

{ cout << treeItem << endl;

}

Then,

// create myTree

BinaryTree myTree;

. . .

// print TreeItems encountered in preorder traversal of myTree

myTree.preorderTraverse( &printItem );

Pointer-Based,Inorder & Postorder Traversal

The functions for Inorder and Postorder traversal of a binary tree are very similar to the function for Preorder traversal, and are left as an exercise.

Nonrecursive Traversal of a Binary Tree

Basic Idea for a Nonrecursive, Inorder Traversal:

1) Push a pointer to the root of the binary tree onto a stack.

2) Follow leftChild pointers, pushing each one onto the stack, until a NULLleftChild pointer is found.

3) Process (visit) the item in this node.

4) Get the node’s rightChild pointer:

• If it is notNULL, then push it onto the stack, and return to step 2 with the leftChild pointer of this rightChild.

• If it is NULL, then pop a node pointer from the stack, and return to step 3. If the stack is empty (so nothing could be popped), then stop — the traversal is done.

Nonrecursive Traversal of a Binary Tree

• The logic for a nonrecursive, preorder or postorder traversal is similar to what was presented on the previous slide for an inorder traversal.

• ~14 lines of code (see chapter 10 of Walls & Mirrors) plus the code for manipulating a stack are required to implement a nonrecursive traversal. Compare this with the 5 lines of code that were required for our recursive solutions.

• This example illustrates how recursion can sometimes be used to produce a clear and concise implementation.

Binary Search Tree Implementationof a Table

Recall that the supported operations for an ADT Table include:

• Create an empty table

• Destroy a table

• Determine whether a table is empty

• Determine the number of items in a table

• Insert a new item into a table

• Delete the item with a given search key from a table

• Retrieve the item with a given search key from a table

• Traverse the items in a table in sorted, search-key order

Table: Binary Search Tree Implementation

typedef string KeyType; // Table search-keys are strings

struct dataItem // all data for an item is put into

{ KeyType key; // one struct for convenience

// other data members are included here

};

typedef dataItem TableItemType; // items in Table are dataItems

// returns tableItem’s searchKey

KeyType getKey( const TableItemType &tableItem )

{ return( tableItem.key );

}

// FunctionType is a pointer to a function with argument

// (TableItemType &) that returns void, used by Table traverse( )

typedef void (*FunctionType) (TableItemType &tableItem);

Table: Binary Search Tree Implementation

typedef TableItemType TreeItemType; // TableItems are stored

struct TreeNode; // in TreeNodes

class Table

{ public:

// declarations of public member functions

private:

TreeNode *root; // root of Binary Search Tree

int size; // number of items in Table

};

struct TreeNode // node in a Binary Search Tree:

{ // place in Implementation file

TreeItemType item;

TreeNode *leftChild; // pointer to TreeNode’s left child

TreeNode *rightChild; // pointer to TreeNode’s right child

};

Table: Binary Search Tree Implementation

An alternative (and perhaps, better) implementation of a Table as a Binary Search Tree would define

struct dataItem

{ KeyType key;

// other data members are included here

};

and

struct TreeNode

{ TreeItemType item;

TreeNode *leftChild;

TreeNode *rightChild;

};

as Classes, with constructors to set the key for a dataItem and to initialize leftChild and rightChild to NULL. getKey( ) would become a public member function, providing access to key.

(See chapter 10 of Walls & Mirrors for details.)

Table: Public Member Function Definitions

// default constructor, which creates a new empty Table

Table::Table( ) : root( NULL ), size( 0 ) { }

// copy constructor, which copies origTable to a new Table

Table::Table( const Table &origTable )

{ copyTree( origTable.root, root );

size = origTable.size;

}

// destructor, which destroys a Table

Table::~Table( )

{ destroyTree( root );

}

Table: Private Member Function Definition

// copies tree rooted at origTreePtr to a new tree rooted at newTreePtr

void Table::copyTree( TreeNode *origTreePtr,

TreeNode *&newTreePtr ) const

{ if( origTreePtr != NULL ) // copy nodes using preorder traversal

{ newTreePtr = new TreeNode;

assert( newTreePtr != NULL );

newTreePtr -> item = origTreePtr -> item;

copyTree( origTreePtr -> leftChild, newTreePtr -> leftChild );

copyTree( origTreePtr -> rightChild, newTreePtr -> rightChild );

}

else

newTreePtr = NULL;

}

Table: Private Member Function Definition

// destroys tree rooted at treePtr

void Table::destroyTree( TreeNode *&treePtr )

{

if( treePtr != NULL )

{ // delete nodes using postorder traversal

destroyTree( treePtr -> leftChild );

destroyTree( treePtr -> rightChild );

delete treePtr;

treePtr = NULL;

}

}

Table: Public Member Function Definitions

// returns true if the Table is empty, otherwise returns false

bool Table::isEmpty( ) const

{ return size = = 0;

}

// returns the number of items in the Table

int Table::length( ) const

{ return size;

}

Table: Public Member Function Definitions

// inserts newItem into a Table in sorted order

bool Table::insert( TableItemType &newItem )

{ if( treeInsertItem( root, newItem ) )

{ size++; return true;

}

return false;

}

// removes item with the given searchKey from a Table

bool Table::remove( KeyType searchKey )

{ if( treeDeleteItem( root, searchKey ) )

{ size – –; return true;

}

return false;

}

Table: Public Member Function Definitions

// retrieves a copy of item with the given searchKey from a Table

bool Table::retrieve( KeyType searchKey,

TableItemType &tableItem ) const

{

return treeRetrieveItem( root, searchKey, tableItem );

}

Table: Private Member Function Definition

// inserts newItem into a Binary Search Tree rooted at treePtr

bool Table::treeInsertItem( TreeNode *&treePtr,

const TreeItemType &newItem )

{ if( treePtr = = NULL )

{ treePtr = new TreeNode;

assert( treePtr != NULL );

treePtr -> item = newItem;

treePtr -> leftChild = treePtr -> rightChild = NULL;

return true;

}

if( getKey( newItem ) = = getKey( treePtr -> item ) ) return false;

if( getKey( newItem ) < getKey( treePtr -> item ) )

return treeInsertItem( treePtr -> leftChild, newItem );

else

return treeInsertItem( treePtr -> rightChild, newItem );

}

Table: Private Member Function Definition

// retrieves a copy of item with the given searchKey from a Binary

// Search Tree rooted at treePtr

bool Table::treeRetrieveItem( TreeNode *treePtr,

KeyType searchKey, TreeItemType &treeItem ) const

{ if( treePtr = = NULL ) return false;

KeyType itemKey = getKey( treePtr -> item );

if( searchKey = = itemKey )

{ treeItem = treePtr -> item; return true;

}

if( searchKey < itemKey )

return treeRetrieveItem( treePtr -> leftChild, searchKey, treeItem );

else

return treeRetrieveItem( treePtr -> rightChild, searchKey, treeItem );

}

Table: Private Member Function Definition

// deletes item with the given searchKey from a Binary Search Tree

// rooted at treePtr

bool Table::treeDeleteItem( TreeNode *&treePtr,

KeyType searchKey )

{ if( treePtr = = NULL ) return false;

KeyType itemKey = getKey( treePtr -> item );

if( searchKey = = itemKey )

{ treeDeleteNode( treePtr ); return true;

}

if( searchKey < itemKey )

return treeDeleteItem( treePtr -> leftChild, searchKey );

else

return treeDeleteItem( treePtr -> rightChild, searchKey );

}

Delete Node at treePtr from a Tree

There are 4 cases:

1) treePtr points to a leaf

2) treePtr points to a node with no leftChild

3) treePtr points to a node with no rightChild

4) treePtr points to a node with both leftChild and rightChild

Table: Private Member Function Definition

// delete node at treePtr from a tree

void Table::treeDeleteNode( TreeNode *&treePtr )

{ if( treePtr -> leftChild = = NULL &&

treePtr -> rightChild = = NULL )

{ /* delete leaf pointed to by treePtr */ }

else if( treePtr -> leftChild = = NULL )

{ /* delete node at treePtr, making treePtr point to rightChild */ }

else if( treePtr -> rightChild = = NULL )

{ /* delete node at treePtr, making treePtr point to leftChild */ }

else

{ /* copy item from leftmost descendant of rightChild */

/* to node at treePtr; delete leftmost descendant */ }

}

60

40

10

70

20

30

50

Case 1: treePtr Points to a Leaf

1) Delete the leaf

2) Set treePtr to NULL

Case 1: treePtr Points to a Leaf

/* delete leaf pointed to by treePtr */

delete treePtr;

treePtr = NULL;

delPtr

70

30

10

80

20

50

40

60

Case 2: treePtr Points to a Node with No leftChild

1) Save treePtr to delPtr

2) Set treePtr to treePtr -> rightChild

3) Delete node at delPtr

Case 2: treePtr Points to a Node with No leftChild

/* delete node at treePtr, making treePtr point to rightChild */

TreeNode *delPtr = treePtr;

treePtr = treePtr -> rightChild;

delPtr -> rightChild = NULL;

delete delPtr;

delPtr

70

60

10

80

20

40

30

50

Case 3: treePtr Points to a Node with No rightChild

1) Save treePtr to delPtr

2) Set treePtr to treePtr -> leftChild

3) Delete node at delPtr

Case 3: treePtr Points to a Node with No rightChild

/* delete node at treePtr, making treePtr point to leftChild */

TreeNode *delPtr = treePtr;

treePtr = treePtr -> leftChild;

delPtr -> leftChild = NULL;

delete delPtr;

nodePtr

80

50

40

70

20

60

30

10

95

90

delPtr

50

treeItem

Case 4: treePtr Points to a Node with Both leftChild and rightChild

1) Let nodePtr be the TreeNode pointer that points to the leftmost descendant of treePtr -> rightChild

2) Save nodePtr -> item to treeItem

3) Save nodePtr to delPtr

4) Set nodePtr to nodePtr -> rightChild

5) Delete node at delPtr

6) Set treePtr -> item to treeItem

Case 4: treePtr Points to a Node with Both leftChild and rightChild

/* copy item from leftmost descendant of rightChild to node */

/* at treePtr; delete leftmost descendant */

TreeItemType leftmostItem;

processLeftmost( treePtr -> rightChild, leftmostItem );

treePtr -> item = leftmostItem;

Table: Private Member Function Definition

/* find leftmost descendant of the node pointed to by nodePtr; */

/* copy its item to treeItem, then delete it */

void Table::processLeftmost( TreeNode *&nodePtr,

TreeItemType &treeItem )

{ if( nodePtr -> leftChild != NULL )

processLeftmost( nodePtr -> leftChild, treeItem );

else

{ treeItem = nodePtr -> item;

TreeNode *delPtr = nodePtr;

nodePtr = nodePtr -> rightChild;

delPtr -> rightChild = NULL;

delete delPtr;

}

}

Table: Public Member Function Definition

// traverses a Table in sorted search-key order, calling

// function visit( ) once for each item in the Table

void Table::traverse( FunctionType visit )

{

treeTraverse( root, visit );

}

Table: Private Member Function Definition

// performs inorder traverse of a Binary Search Tree, calling

// function visit( ) once at each node in the tree

void Table::treeTraverse( TreeNode *treePtr,

FunctionType visit )

{ if( treePtr != NULL )

{

treeTraverse( treePtr -> leftChild, visit );

visit( treePtr -> item );

treeTraverse( treePtr -> rightChild, visit );

}

}

Treesort: Basic Idea

Problem: Sort an array of items into search-key order.

1) Insert items from the array into a Binary Search Tree (or Binary-Search-Tree-based Table).

2) Perform an inorder traversal of the Binary Search Tree, copying each item back into the array.

When step 2 is done, the array will be in sorted order!

void treeSort( TableItemType a[ ], int n )

{ Table table;

// insert items from a[ ] into table

for( int i = 0; i < n; i++ )

table.insert( a[i] );

// copy items from table into a[ ] in sorted, search-key order

table.traverse( &copyItem, a );

}

void copyItem( TableItemType &tableItem, TableItemType a[ ] )

{ static int k = 0;

a[k++] = tableItem;

}

typedef void (*FunctionType2) (TableItemType &tableItem,

TableItemType a[ ] );

void Table::traverse( FunctionType2 visit, TableItemType a[ ] )

{ treeTraverse( root, visit, a );

}

void Table::treeTraverse( TreeNode *treePtr,

FunctionType2 visit, TableItemType a[ ] );

{ if( treePtr != NULL )

{ treeTraverse( treePtr -> leftChild, visit, a );

visit( treePtr -> item, a );

treeTraverse( treePtr -> rightChild, visit, a );

}

}

Treesort: Efficiency

• Each insertion into a Binary Search Tree requires O( log n ) operations in the best and average cases and O( n ) operations in the worst case.

• So, performing ninsertions requires O( n * log n ) operations in the best and average cases and O( n2 ) operations in the worst case.

• Traversal of the Binary Search Tree requires O( n ) operations in allcases.

• Therefore, the overallGrowth Rate of Treesort is O( n * log n ) operations in the best and average cases and O( n2 ) operations in the worst case — the same as Quicksort.

• Binary-Search-Tree algorithms are efficient as long as the tree is balanced. If not balanced, Binary-Search-Tree algorithms can become as inefficient as algorithms on a linear List. We will learn about maintaining balanced trees in the coming chapters.