500 likes | 764 Views
DATA STRUCTURES AND ALGORITHMS. Lecture Notes 5 Prepared by İnanç TAHRALI. ROAD MAP. TREES Definitions and Terminology Implementation of Trees Tree Traversals Binary Trees The Search Tree ADT-Binary Search Trees AVL Trees. TREES : Definition. Recursive Definition :
E N D
DATA STRUCTURES ANDALGORITHMS Lecture Notes 5 Prepared by İnanç TAHRALI
ROAD MAP • TREES • Definitions and Terminology • Implementation of Trees • Tree Traversals • Binary Trees • The Search Tree ADT-Binary Search Trees • AVL Trees
TREES: Definition Recursive Definition : • Tree is a collection of nodes • A tree can be empty • A tree contains zero or more subtrees T1, T2,… Tk connected to a rootnode by edges
TREES: Terminology Family Tree Terminology • child F is child of A • parent A is the parent of F • each node is connected to a parent except the root • sibling nodes with same parents (K, L, M) • leaf nodes with no children (P, Q) • Ancestor / Descendant
Path : a sequence of nodes n1, n2, … nk, where ni is the parent of ni+1 1≤i<k • Lenght : number of edges on the path (k-1) • Depth : depth of ni is the lenght of unique path from the root to ni • depth of root is 0 • depth of a tree = depth of the deepest leaf • Height : height of ni is the lenght of the longest path from ni to a leaf • height of a leaf is 0 • height of a tree = height of the root = depth of the tree
Implementation of Trees 1. Each node contains a pointer to each of its children • number of children would be large 2. Each node contains an array of pointers to its children • number of children may vary greatly (waste of space)
Implementation of Trees 3. Each node contains a linked list of the children struct TreeNode { Object element; TreeNode *firstChild; TreeNode *nextSibling; }
ROAD MAP • TREES • Implementation of Trees • Tree Traversals • Binary Trees • The Search Tree ADT-Binary Search Trees • AVL Trees
Tree Traversals • One of the most popular applications of trees is the directory structure of O/S
Preorder Tree Traversals • work on the node first before its children ! Pseudocodeto list a directory in a hierarchical file system void FileSystem::listAll(int depth = 0)const{ printName(depth); if (isDirectory()) for each file c in this directory (foreach child) c.listAll(depth+1); }
Postorder Tree Traversals • work on the node after its children ! Pseudocode to calculate the size of a directory int FileSystem::size () const{ int totalSize = sizeOfThisFile (); if (isDirectory()) for each file c in this directory totalSize += c.size(); return totalsize; }
ROAD MAP • TREES • Implementation of Trees • Tree Traversals • Binary Trees • The Search Tree ADT-Binary Search Trees • AVL Trees
Binary Trees • Definition : A tree in which nodes have at most two children Generic Binary Tree
Binary Trees Binary Tree Worst case binary tree
Implementation of Binary Trees • keep a pointer to left child and right child struct BinaryNode { Object element; BinaryNode *left; BinaryNode *right; }
Example: Expression Trees • Leaves contain operands • Internal nodes contain operators • Inorder traversal => infix expression • Preorder traversal => prefix expression • Postorder traversal => postfix expression
Expression Trees • Entire tree represents (a+(b*c))+(((d*e)+f)*g) • Left subtree represents a+(b*c) • Right subtree represents ((d*e)+f)*g
Constructing an Expression Tree Algorithm to convert a postfix expresion into an expression tree • read the expression one symbol at a time. • if the symbol is operand • create a one-node tree • push the tree onto a stack • if the symbol is operator • pop two trees T1 and T2 from the stack • form a new tree whose root is the operator and whose left and right subtrees are T2 and T1 respectively • This new tree is pushed onto the stack
Example: input is ab+cde+** • First two symbols are operands • create one-node trees • push pointers to them onto a stack • Next + is read • pointers to trees are poped • a new tree is formed • a pointer to it is pushed onto the stack
Example: input is ab+cde+** • c, d, e are read • for each a one-node tree is created • A pointer to the corresponding tree is pushed onto the stack.
Example: input is ab+cde+** • + is read • two trees are merged
Example: input is ab+cde+** • * is read • pop two tree pointers and form a new tree with a * as root
Example: input is ab+cde+** • Last symbol is read • two trees are merged • a pointer to the final tree is left on the stack
ROAD MAP • TREES • Implementation of Trees • Tree Traversals • Binary Trees • The Search Tree ADT-Binary SearchTrees • AVL Trees
Binary Search Trees Each node in tree stores an item • items are integers and distinct • deal with dublicates later Properties • A binary tree • for each node x • values at left subtree are smaller • values at right subtree are larger than the value of x
Binary Search Trees Which one of the trees below is binary search tree ?
Binary Search Trees template <class Comparable> class BinarySearchTree template <class Comparable> class BinaryNode { Comparable element; BinaryNode *left; BinaryNode *right; BinaryNode( const Comparable & theElement, BinaryNode *lt, BinaryNode *rt ): element( theElement ), left( lt ), right( rt ) { } friend class BinarySearchTree <Comparable> };
template <class Comparable> class BinarySearchTree { public: explicit BinarySearchTree(constComparable & notFound); BinarySearchTree( const BinarySearchTree & rhs ); ~BinarySearchTree( ); const Comparable & findMin( ) const; const Comparable & findMax( ) const; const Comparable & find (constComparable & x) const; bool isEmpty( ) const; void printTree( ) const; void makeEmpty( ); void insert( const Comparable & x ); void remove( const Comparable & x ); const BinarySearchTree & operator= ( const BinarySearchTree & rhs ); private: BinaryNode < Comparable > *root; const Comparable ITEM_NOT_FOUND;
int main( ){ const int ITEM_NOT_FOUND = -9999; BinarySearchTree<int> t( ITEM_NOT_FOUND ); int NUMS = 4000; const int GAP = 37; int i; for( i = GAP; i != 0; i = ( i + GAP ) % NUMS ) t.insert( i ); for( i = 1; i < NUMS; i+= 2 ) t.remove( i ); if( NUMS < 40 )t.printTree( ); if( t.findMin( ) != 2 || t.findMax( ) != NUMS - 2 ) cout << "FindMin or FindMax error!" << endl; for( i = 2; i < NUMS; i+=2 ) if( t.find( i ) != i )cout << "Find error1!" << endl; for( i = 1; i < NUMS; i+=2 ){ if( t.find( i ) != ITEM_NOT_FOUND ) cout << "Find error2!"<< endl;} BinarySearchTree<int> t2( ITEM_NOT_FOUND ); t2 = t; for( i = 2; i < NUMS; i+=2 ) if( t2.find( i ) != i )cout << "Find error1!" << endl; return 0; }
template <class Comparable> class BinarySearchTree { public: explicit BinarySearchTree(constComparable & notFound); BinarySearchTree( const BinarySearchTree & rhs ); ~BinarySearchTree( ); const Comparable & findMin( ) const; const Comparable & findMax( ) const; const Comparable & find (constComparable & x) const; bool isEmpty( ) const; void printTree( ) const; void makeEmpty( ); void insert( const Comparable & x ); void remove( const Comparable & x ); const BinarySearchTree & operator= ( const BinarySearchTree & rhs ); private: BinaryNode < Comparable > *root; const Comparable ITEM_NOT_FOUND;
private: const Comparable & elementAt ( BinaryNode<Comparable> *t) const; void insert ( const Comparable & x, BinaryNode<Comparable> * & t ) const; void remove ( const Comparable & x, BinaryNode<Comparable> * & t ) const; BinaryNode<Comparable> * findMin ( BinaryNode<Comparable> *t ) const; BinaryNode<Comparable> * findMax ( BinaryNode<Comparable> *t ) const; BinaryNode<Comparable> * find ( const Comparable & x, BinaryNode<Comparable> *t ) const; void makeEmpty ( BinaryNode<Comparable> * & t ) const; void printTree ( BinaryNode<Comparable> *t ) const; BinaryNode<Comparable> * clone ( BinaryNode<Comparable>) *t ) const; };
find /* Find item x in the tree - Return the matching item or ITEM_NOT_FOUND if not found. */ template <class Comparable> const Comparable & BinarySearchTree<Comparable>:: find( const Comparable & x ) const { return elementAt( find( x, root ) ); } template <class Comparable> const Comparable & BinarySearchTree<Comparable>:: elementAt( BinaryNode<Comparable> *t ) const { if( t == NULL ) return ITEM_NOT_FOUND; else return t->element; }
find /* Find item x in the tree - Return the node containinig the matching item or NULL if not found. */ template <class Comparable> BinaryNode<Comparable> * BinarySearchTree<Comparable>:: find ( const Comparable & x, BinaryNode<Comparable> *t ) const; { if (t==NULL) return NULL; else if (x < t->element) return find( x, t->left ); else if (t->element < x) return find( x, t->right ); else retun t; }
Recursive implementation of findMin /* Internal method to find the smallest item in a subtree t. */ template <class Comparable> BinaryNode<Comparable> * BinarySearchTree<Comparable>::findMin( BinaryNode<Comparable> *t ) const { if( t == NULL ) return NULL; if( t->left == NULL ) return t; return findMin( t->left ); }
Non-recursive implementation of findMax template <class Comparable> BinaryNode<Comparable> * BinarySearchTree<Comparable>::findMax( BinaryNode<Comparable> *t ) const { if( t != NULL ) while( t->right != NULL ) t = t->right; return t; }
insert into a binary search tree template <class Comparable> void BinarySearchTree<Comparable>:: insert( const Comparable & x, BinaryNode<Comparable> * & t ) const { if( t == NULL ) t = new BinaryNode<Comparable>( x, NULL, NULL ); else if( x < t->element ) insert( x, t->left ); else if( t->element < x ) insert( x, t->right ); else ; // Duplicate; do nothing }
Remove template <class Comparable> void BinarySearchTree<Comparable>:: remove( const Comparable & x, BinaryNode<Comparable> * & t ) const { if( t == NULL ) return; if( x < t->element ) remove( x, t->left ); else if( t->element < x ) remove( x, t->right ); else if( t->left != NULL && t->right != NULL ) { t->element = findMin( t->right )->element; remove( t->element, t->right ); } else { BinaryNode<Comparable> *oldNode = t; t = ( t->left != NULL ) ? t->left : t->right; delete oldNode; } }
Destructor and recursive makeEmpty /* Destructor for the tree. */ template <class Comparable> BinarySearchTree<Comparable>::~BinarySearchTree( ){ makeEmpty( ); } template <class Comparable> void BinarySearchTree<Comparable>:: makeEmpty( BinaryNode<Comparable> * & t ) const { if( t != NULL ) { makeEmpty( t->left ); makeEmpty( t->right ); delete t; } t = NULL; }
Operator = template <class Comparable> const BinarySearchTree<Comparable> & BinarySearchTree<Comparable>:: operator=( const BinarySearchTree<Comparable> & rhs ) { if( this != &rhs ){ makeEmpty( ); root = clone( rhs.root ); } return *this; }
Recursive clone member function template <class Comparable> BinaryNode<Comparable> * BinarySearchTree<Comparable>::clone( BinaryNode<Comparable> * t ) const { if( t == NULL ) return NULL; else return new BinaryNode<Comparable>( t->element, clone( t->left ), clone( t->right ) ); }