580 likes | 736 Views
240-222 Computer Programming Techniques Semester 1, 1998. 16. Trees. Objective of these slides: to discuss trees coded in C. Overview. 1. Tree Example 2. Binary Trees 3. Binary Trees in C 4. Tree Traversal 5. Binary Search Trees 6. Searching a BST 7. Insertion into a BST
E N D
240-222 Computer Programming TechniquesSemester 1, 1998 16. Trees Objective of these slides: to discuss trees coded in C
Overview 1. Tree Example 2. Binary Trees 3. Binary Trees in C 4. Tree Traversal 5. Binary Search Trees 6. Searching a BST 7. Insertion into a BST 8. Deletion from a BST
1. Tree Example Board of Directors ResearchDivision Manufacturing Division Admin Marketing Computer Systems Accounts Payable Payroll
2. Binary Trees • Each element (node) of the tree may have 0,1 or 2 successors. a c b d e f g h i j k
Binary Tree Jargon • a is the root of the tree • b, c are the children of a • left subtree of a: the tree whose root is b • right subtree of a: the tree whose root is c • d, e, h, i, j are descendents of b • every node is a descendent of a (the root) • h, i, j, k, g are the leaves of the tree
Shape Examples for 6 nodes:
Some Binary Tree ADT Operations • create an empty tree • build a new tree from a data value and two subtrees • deletion • insertion • check to see if a tree is empty • print out all the elements in a tree
3. Binary Trees in C 3.1. Binary Tree Type 3.2. Examples 3.3. Some Functions 3.4. Size of a Binary Tree 3.5. Height of a Binary Tree
3.1. Binary Tree Type Fig 12.19 struct treenode { struct treenode *leftptr; int data; struct treenode *rightptr;};typedef struct treenode TREENODE;typedef TREENODE *TREE; treenode data leftptr rightptr
3.2. Examples TREE t;The empty tree: t = NULL;A tree with a single element 2: t t NULL t 2 N N
t 2 A more complicated tree: 1 4 N N N 7 N N
3.3. Some Functions int isEmptyTree(TREE t){ if (t == NULL) return 1; /* true */ else return 0; /* false */}
int value(TREE t){ if (isEmptyTree(t)) { printf(“Tree is empty\n”); return -1; } else return t->data;} TREE mkEmpty(void)/* return an empty tree */{ return NULL;}
TREE mkTree(int x, TREE leftT, TREE rightT)/* make a new tree from a data value x and two existing trees */{ TREE temp; temp = malloc(sizeof(TREENODE)); temp->data = x; temp->leftptr = leftT; temp->rightptr = rightT; return temp;}
TREE lsTree(TREE t){ return t->leftptr; /* don’t bother dealing with the empty tree case */}TREE rsTree(TREE t){ return t->rightptr; }
3.4. Size of a Binary Tree • an empty tree has 0 size • a non-empty tree has one node plus the number of elements in the subtrees n size(tree) = 1 + size(tree1) + size(tree2) tree1 tree2
C Version int size(TREE t){ if (isEmptyTree(t)) return 0; else return (1 + size(lsTree(t)) + size(rsTree(t)) );}
Rephrased int size(TREE t){ if (t == NULL) return 0; else return (1 + size(t->leftptr) + size(t->rightptr) );}
3.5. Height of a Binary Tree • the height of an empty tree is 0 • the height of a non-empty tree is 1 plus the height of the highest subtree n height(tree) = 1 + max(height(tree1), height(tree2)) heightof tree1 height of tree2 tree1 tree2
C Version int height(TREE t){ if(isEmptyTree(t)) return 0; else return (1 + max(height(lsTree(t)), height(rsTree(t))));}
4. Tree Traversal A traversal is when all the nodes (elements) of a data structure are visited. 4.1. Tree Traversal Methods 4.2. Example 4.3. Print a Tree using Inorder 4.4. Preorder and Postorder Printing
4.1. Tree Traversal Methods T L R • Preorder Traversal (T-L-R) • look at the root first, then the left subtree, then the right subtree • Inorder Traversal (L-T-R) • look at the left subtree first, then the root, then the right subtree • Postorder Traversal (L-R-T) • look at the left subtree first, then the right subtree, then the root
4.2. Example 1 3 TraversalNodes Visited preorder. . . . . . 1 2 4 8 5 9 10 3 6 11 7 inorder. . . . . . . 8 4 2 9 5 10 1 6 11 3 7 postorder. . . . . 8 4 9 10 5 2 11 6 7 3 1 2 4 5 6 7 8 9 10 11
4.3. Print a Tree using Inorder void inorder_print(TREE t){ if (!isEmptyTree(t)) { inorder_print(lsTree(t)); printf(“%3d”, value(t)); inorder_print(rsTree(t)); }}Also see Fig. 12.9 of D&D.
4.4. Preorder and Postorder Printing void preorder_print(TREE t){ if (!isEmptyTree(t)) { printf(“%3d”, value(t)); preorder_print(lsTree(t)); preorder_print(rsTree(t)); }}
void postorder_print(TREE t){ if (!isEmptyTree(t)) { postorder_print(lsTree(t)); postorder_print(rsTree(t)); printf(“%3d”, value(t)); }} • Also see Fig. 12.9 of D&D.
5. Binary Search Trees 5.1. Informal Definition 5.2. Examples 5.3. C BST Type
5.1. Informal Definition • A Binary Search Tree (BST) is a binary tree, with an ordering on its nodes. • In every subtree (including the whole tree): • all values in the left subtree are 'less than' the value in the root node • all values in the right subtree are 'greater than' the value in the root node
5.2. Examples 4 2 6 is a BST 7 1 3 5 4 is not a BST 2 6 7 3 1 5
5.3. C BST Type Change the typedef names to reflect the fact that we are treating the tree as a BST: typedef struct treenode BSTNODE;typedef BSTNODE *BST; • C’s typing is not powerful enough to include the BST ordering information
6. Searching a BST 6.1. Informal Definition 6.2. Example 6.3. C Version
6.1. Informal Definition To recursively search for an item (called the key) in a BST: • A key cannot be in an empty tree • For a non-empty tree: • if key == root value, stop • if key < root value, search left subtree • if key > root value, search right subtree
6.2. Example • Consider searching for 5: 4 2 6 7 1 3 5
6.3. C Version int bstsearch(int key, BST t){ int v; if (isEmptyTree(t)) return 0; v = value(t); if (key == v) return 1; if (key < v) return bstsearch(key, lsTree(t)); if (key > v) return bstsearch(key, rsTree(t));}
7. Insertion into a BST 7.1. Examples 7.2. Informal Insertion Definition 7.3. Tree Creation Functions 7.4. bstinsert() 7.5. More Efficient Insertion 7.6. Comparing bstinsert() and insert_node() 7.7. insert_node2()
7.1. Examples Insert the following into an empty BST:4 2 3 6 1 5 7 The resulting tree: 4 2 6 7 1 3 5
5 1 7 6 2 4 3 Rearrange the values, and reinsert them:5 7 1 4 6 2 3 The resulting tree:
7.2. Informal Insertion Definition 1. If the tree is empty, the value becomes the root of a new tree. If the tree is not empty, then: 2. If value < root, it must be inserted into the left subtree. 3. If value > root, it must be inserted into the right subtree. 4. If value == root, then stop.
7.3. Tree Creation Functions BST mkEmpty(void){ return NULL;}BST mkTree(int x,BST leftT, BST rightT){ BST t; t = malloc(sizeof(BSTNODE)); t->data = x; t->leftptr = leftT; t->rightptr = rightT; return t;}
7.4. bstinsert() BST bstinsert(int x, BST t){ int v; BST t1, t2; if (isEmptyTree(t)) return mkTree(x,mkEmpty(),mkEmpty()); v = value(t); t1 = lsTree(t); t2 = rsTree(t); continued
if (x < v) return mkTree(v,bstinsert(x,t1),t2); else if (x > v) return mkTree(v,t1,bstinsert(x,t2)); else return mkTree(v, t1, t2); /* or return t; */} • easy to understand • inefficient due to copying
Use: BST t, newt;t = bstinsert(5, bstinsert(7, bstinsert(1, bstinsert(2, bstinsert(4, mkEmpty())))));newt = bstinsert(9, t);
4 2 7 1 5 newt t 4 7 9 • bstinsert() has copied all of the nodes in the path from the root down to the parent node of where the number has been inserted.
7.5. More Efficient Insertion Modify the input tree to include the new value. • no copying • destructive assignment
insert_node() similar to Fig 12.19 void insert_node(BST *tp, int value){ /* tp is a pointer to a BST */ if (*tp == NULL) { *tp = malloc(sizeof(BSTNODE)); (*tp)->data = value; (*tp)->leftptr = NULL; (*tp)->rightptr = NULL; } else if (value < (*tp)->data ) insert_node(&((*tp)->leftptr), value); else if (value > (*tp)->data ) insert_node(&((*tp)->rightptr), value); else printf("duplicate node\n");}
Use: BST t = NULL;insert_node(&t, 4); /* address of pointer */insert_node(&t, 2);insert_node(&t, 5);insert_node(&t, 7);
What is &((*tp)->leftptr) ? tp is a pointer to a BST *tp is a BST (*tp)->leftptr is the left subtree, another BST &((*tp)->leftptr) is the address of that BST, which is the type of the first arg of insert_node() • The same reasoning applies to the use of:&((*tp)->rightptr)
7.6. Comparing bstinsert() and insert_node() • bstinsert() • easy to understand but inefficient • no destructive assignment • copying • insert_node() • efficient but hard to understand • destructive assignment • call by reference
7.7. insert_node2() /* call by reference replaced by returns */BST insert_node2(BST t, int value){ if (t == NULL) { t = malloc(sizeof(BSTNODE)); t->data = value; t->leftptr = NULL; t->rightptr = NULL; } continued
else if (value < t->data) t->leftptr = insert_node2(t->leftptr, value); else if (value > t->data) t->rightptr = insert_node2(t->rightptr, value); else printf("duplicate node\n"); return t;}