Binary Trees: Traversals, Operations, and Binary Search Trees, Study notes of Computer Science

An overview of binary trees, including their definition, traversal algorithms (preorder, inorder, postorder), and various operations such as finding the maximum value, summing the tree, and inserting and deleting nodes. The document also introduces binary search trees and their insertion and deletion algorithms.

Typology: Study notes

Pre 2010

Uploaded on 11/08/2009

koofers-user-5pa
koofers-user-5pa 🇺🇸

5

(1)

10 documents

1 / 12

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Binary Trees
The traversal algorithms that appeared in the previous set of notes make exploit
the fact that a binary tree can be recursively defined as:
A binary tree is:
empty, or
a node (the root) with two binary trees called the left subtree and
the right subtree of the root.
Let’s examine the inorder traversal algorithm again:
Consider the following binary tree and produce the inorder traversal using the
algorithm above. (For practice do the preorder and postorder traversals as well.)
Binary Trees - 1
Data Structures: Binary Trees
void inorder( struct treeNode *p)
{
if (p != NULL)
{ inorder(p->left);
printf(“%d\n”, p->data);
inorder(p->right);
}
}
A
B C
D E
F G
Answers:
preorder traversal: A B C D F G E
inorder traversal: B A F D G C E
postorder traversal: B F G D E C A
pf3
pf4
pf5
pf8
pf9
pfa

Partial preview of the text

Download Binary Trees: Traversals, Operations, and Binary Search Trees and more Study notes Computer Science in PDF only on Docsity!

Binary Trees

The traversal algorithms that appeared in the previous set of notes make exploit the fact that a binary tree can be recursively defined as: A binary tree is:  empty, or  a node (the root) with two binary trees called the left subtree and the right subtree of the root. Let’s examine the inorder traversal algorithm again: Consider the following binary tree and produce the inorder traversal using the algorithm above. (For practice do the preorder and postorder traversals as well.) Binary Trees - (^1)

Data Structures: Binary Trees

void inorder( struct treeNode *p) { if (p != NULL) { inorder(p->left); printf(“%d\n”, p->data); inorder(p->right); } } A B C D E F G Answers: preorder traversal: A B C D F G E inorder traversal: B A F D G C E postorder traversal: B F G D E C A

An inorder traversal of this binary tree produces: B A F D G C E. Notice that the “search” for a node to print moves as deeply as possible in the left subtree before ever considering the right subtree. This is called a depth-first traversal. The preorder and postorder traversals are also depth-first traversals. Now let’s perform some other operations on binary trees. Suppose that we want to find the largest value in a binary tree. The following algorithm will accomplish this task. Trace of algorithm findMax int findMax (struct treeNode *p) { int root_value, left, right, max; max = -1 //assume all values in the tree are positive integers if (p!= NULL) { root_value = p -> data; left = findMax( p -> left); right = findMax( p -> right ); //find the largest of the tree values. if (left > right) max = left; else max = right; if (root_value > max) max = root_value; } return max; } struct treeNode { int data; struct treeNode *left; struct treeNode *right; };

yourself to see if you can produce a correct recursive algorithm to solve this problem. Trace of algorithm sumTree Let’s trace the execution of algorithm sumTree on the tree shown below: answer = return( 40 + add(p->left) + add(p->right)) = 40 + 54 + add(p->left) + add(p->right) + add(p->right)) = 40 + 54 + 0 + 0 + add(p->right) = 40 + 54 + 0 + 0 + 13 + add(p->left) + add(p->right) = 40 + 54 + 0 + 0 + 13 + 23 + 0 + 0 + add(p->right ) = 40 + 54 + 0 + 0 + 13 + 23 + 0 + 0 + 77 + add(p->left) + add(p->right) = 40 + 54 + 0 + 0 + 13 + 23 + 0 + 0 + 77 + 0 + 0 = 94 + 36 + 77 = 207 Binary Search Trees A binary search tree is a binary tree that is either empty or in which each node contains a data value that satisfies the following: int sumTree (struct treeNode *p) { if (p != NULL) return( p->data + add(p->left) + add(p->right)); else return 0; } 40 54 13 23 77

  1. All data values in the left subtree are smaller than the data value in the root.
  2. The data value in the root is smaller than all values in its right subtree.
  3. The left and right subtrees are also binary search trees. A binary search tree (often abbreviated to BST) allows for fast searching. It amounts to embedding the binary search into the data structure. Shown below is an example BST. A binary search tree Obviously, a BST is designed for quick searching and this is an extremely common operation on this data structure and it is the first algorithm that we present for it. Insertion in a BST Inserting a new node into a BST always occurs at a NULL pointer. There is never a case when existing nodes need to be rearrange to accommodate the new node. As an example, consider inserting the new value 43 into the BST 59 18 67 13 32 63 72 25 void BSTsearch( struct treeNode *p, int target) { if (p != NULL) if (p-> data == target) //success found target in BST printf(“The tree contains %d\n”, target); else if (p->data < target) BSTsearch(p->left, target); else BSTsearch(p->right, target); }

(3) deletion of an internal node with two children (has both a left and right subtree. We’ll examine each case separately: Deletion of a Leaf Node Since a leaf node has empty left and right subtrees, deleting a leaf node will render a tree with one less node but which remains a BST. This is illustrated below: A BST with a leaf node The BST with the leaf node marked for deletion deleted. A BST remains Deletion of a Node with One Child When the node has one child the case is also not too complicated, but is more so than deleting a leaf node. The parent’s reference to the node is reset to refer to the deleted node’s child. This has the effect of lifting up the deleted node’s children by one level in the tree. (All great-great-…-grandchildren will lose one great from their kinship designations.) An example is shown below. A BST with an internal node having only one child marked to be deleted Binary Trees - (^7) 5 1 6 3 7 2 4 5 1 6 3 7 2 5 1 6 3 7 2

The marked internal node has only a right subtree so the parent of the deleted node will now reference the deleted node’s child Note that it makes no difference if the node to be deleted has only a left or a right child. The previous example illustrated the case when the only child was a right child. The next example illustrates the case when the only child is a left child. Initial BST with the node to be deleted shown in green. Its only child is a left child The BST after the deletion has occurred Notice that essentially all that occurred to delete an internal node with a single child is the parent of the deleted node becomes the parent of what formerly were its grandchildren. Deletion of a Node with Two Children 5 6 7 3 2 9 5 7 16 6 2 7 3 2 4 9 5 16 6 2 7 3 2 4

We could have, just as easily, found the immediate successor of 18 which is the leftmost node it is right subtree and put this value into the place currently occupied by 18. This case is shown below. Notice that in both cases, the node which is physically deleted from the BST is a leaf node, and this is the trivial deletion case. Also notice, that while there is no fundamental difference is selecting the immediate predecessor or the immediate successor as the replacement for the deleted value, in reality there may be a difference. The example above, illustrates, to some degree, this difference which results from a potential difference in the heights of the two subtrees. In the example above, the immediate predecessor was the better choice since it was only one level away from the node to be deleted and therefore our search to find this node would be shorter than the search to find the immediate successor which was two levels away. While a few levels difference in the location of the immediate predecessor and immediate successor may not make much difference, it certainly will if there is a big difference between the two heights and obviously, the shorter the height the quicker the search and this is the way to go. 43 59 25 67 13 32 63 72

Practice Problems Shown below are three problems for you to practice writing algorithms for operations on binary trees. As usual, try these before you look at the answers on the last page of this set of notes for a possible solution. Since the tree has a naturally occurring recursive definition, make your functions recursive.

  1. Write a function that will count the number of leaf nodes in a binary tree.
  2. Write a function that will find the height of a binary tree. The height of an empty tree is defined a zero. The height of a single node tree is defined as 1.
  3. Write a function that will interchange all the left and right subtrees in a binary tree. Solutions to Practice Problems Solution to Practice Problem # int number_of_leaves (struct treeNode *p) { if (p!= NULL) if (p->left == NULL && p->right == NULL) return 1; else return (number_of_leaves(p->left) + number_of_leaves(p->right); else return 0; }