230 likes | 321 Views
Introduction to C Programming CE00312-1. Lecture 23 Binary Trees. Binary Search Tree. A binary tree has a maximum of two branches. A binary search tree has some further characteristics:
E N D
Introduction to C ProgrammingCE00312-1 Lecture 23 Binary Trees
Binary Search Tree • A binary tree has a maximum of two branches. • A binary search tree has some further characteristics: • 1) With respect to any particular node in the tree, all those nodes in the left sub-tree have data which are less (alphabetically for strings) than the node, and all those in the right sub-tree are greater.
A Binary Search Tree root of tree fred teddy colin nick brian darryl thomas fong rob a leaf
Searching a Binary Search Tree • 2) A search for a particular data item, only involves searching down one branch at each node. • In the example, searching for “fong” involves going left at “fred” (“fong” < “fred”), then right at “colin” (“fong” > “colin”), then right at “darryl” (“fong” > “darryl”) and then finding “fong” as a leaf.
Inserting into a Binary Search Tree root of tree fred teddy colin nick brian darryl thomas node to insert claude fong rob a leaf
Insertion into a Binary Search Tree • 3) Insertion of a new node is similar to a search, and then linking in a new leaf for that node. • In the example, a new node for “claude” would be inserted to the right of “brian”, because “claude” is less than both “fred” and “colin” but not “brian”. • 4) An Inorder Traversal of the tree yields all the nodes in order (alphabetical for strings).
Efficiency • Searching, insertion, deletion and sorting (see below) are efficient because half the tree is eliminated at each comparison (cf binary search with arrays). • In searching for an item in a binary search tree only involves going left or right for each node as we descend the tree. This is similar to choosing first or second half during a binary search for an array. • Eliminating half the data with each comparison implies the total number of comparisons is log2 n for n items. • However, this is only guaranteed if the tree is balanced!
A Binary Tree as a Linked List root fred N U L L N U L L N U L L darryl teddy N U L L N U L L nick
left data right Structure of a tree node right sub-tree left sub-tree
Header for Binary Search Tree • Let us define a header file called “tree.h” containing all our types, structures and tree function prototypes. • This file can be included in all files that need to use binary search trees. • We shall also keep all our tree functions in “tree.c” and an application in “treegrow.c”. • All these may be compiled by: cc treegrow.c tree.c
Header file “tree.h” #include "stdio.h“ // for I/O and NULL #include "stdlib.h“ // for malloc #include "string.h" // for strings struct node { struct node *left; // left branch char data[21]; // string data struct node *right; // right branch }; typedef struct node *Treepointer; // new type called Treepointer
Prototypes for binary search trees void inorder(Treepointer); // traverse tree void insert(Treepointer, Treepointer); // insert a node into a tree Treepointer createnode(char []); // create a node for an item Treepointer delete(Treepointer, char []); // delete an item from a tree
Inorder Traversal • A traversal involves visiting all the nodes in the tree in a particular sequence. • The most commonly used one is the inorder traversal. • Inorder traversal • visits all the nodes to left of the given node, • then the given node itself and • then visits all those to the right. For a binary search tree this yields the data in sort order.
Traversing a binary search tree root of tree fred teddy colin nick brian darryl thomas fong rob a leaf
Traversals are recursive • Any function that visits all the nodes in a tree has to be recursive. • All traversal algorithms should be recursive. • Iterative (using while loops) solutions are extremely cumbersome - not to mention very difficult - to write. • This should be expected because trees themselves are recursive data structures - every tree has branches which are themselves subtrees.
Inorder Traversal #include "tree.h" void inorder(Treepointer T) { // traverse the tree, T if (T != NULL) { inorder(T -> left); // traverse left printf("%s\n", T -> data);// print data inorder(T -> right); // traverse right } // else empty tree do nothing } To print all nodes in alphabetical order use: inorder (root);
Inorder Traversal can give the same result for different trees. • Using the normal infix notation, brackets would have to be used to distinguish (A + B) * C from A + B * C E.G. (2 + 3) * 4 2 + 3 * 4 Give 20 14
Reverse Polish • However, postorder traversal gives different results for different trees. • Thus, reverse polish notation can represent algebraic trees faithfully without the use of either brackets or operator precedences! • A B + C * (do A B + first) is different from A B C * + (do B C * first) • Hence the use of reverse polish by compilers
Postorder traversal • Postorder traversal is almost the same as inorder traversal – both have to visit all the same nodes – but in a different sequence. • The recursive algorithm should be very similar as the two traversals do similar things. • Only two statements are swapped, so that for a postorder traversal, the right subtree is visited before printing the current node, T.
Postorder Traversal #include "tree.h" void postorder(Treepointer T) { // traverse the tree, T if (T != NULL) { postorder(T -> left); // traverse left postorder(T -> right);// traverse right printf("%s ", T -> data);// print data } // else empty tree do nothing } To print all nodes in reverse polish use: postorder (root);