Binary trees

49
1 Binary Trees

Transcript of Binary trees

Page 1: Binary trees

1

Binary Trees

Page 2: Binary trees

2

Definition and Applications of Binary Trees

• A binary tree is a non-linear linked list where each node may point to two other nodes.

Page 3: Binary trees

3

Definition and Applications of Binary Trees

• It is anchored at the top by a tree pointer, which is like the head pointer in a linked list.

• The first node in the list is called the root node.

• The root node has pointers to two other nodes, which are called children, or child nodes.

Page 4: Binary trees

4

Definition and Applications of Binary Trees

• A node that has no children is called a leaf node.

• All pointers that do not point to a node are set to NULL.

Page 5: Binary trees

5

Definition and Applications of Binary Trees

• Binary trees can be divided into subtrees. A subtree is an entire branch of the tree, from one particular node down.

Page 6: Binary trees

6

Definition and Applications of Binary Trees

• Binary trees are excellent data structures for searching large amounts of information. They are commonly used in database applications to organize key values that index database records.

• When used to facilitate searches, a binary tree is called a binary search tree.

Page 7: Binary trees

7

Definition and Applications of Binary Trees

• Information is stored in binary search trees in a way that makes a binary search simple. For example, look at Figure 3.

Values are stored in a binary tree so that a node's left child holds data whose value is less than the node's data, and the node's right child holds data whose value is greater tan the node's data.

Page 8: Binary trees

8

Definition and Applications of Binary Trees

• It is also true that all the nodes to the left of a node hold values less than the node's value. Likewise, all the nodes to the right of a node hold values that are greater than the node's data.

• When an application is searching a binary tree, it starts at the root node. If the root node does not hold the search value, the application branches either to the left or right child, depending on whether the search value is less than or grater than the value at the root node.

Page 9: Binary trees

9

Definition and Applications of Binary Trees

• This process continues until the value is found. Figure 4 illustrates the search pattern for finding the value P in the binary tree.

Page 10: Binary trees

10

Binary Search Tree Operations• Creating a Node: We will demonstrate binary tree

operations using the IntBinaryTree class. • The basis of our binary tree node is the following struct

declaration:

struct TreeNode{

int value;TreeNode *left;TreeNode *right;

};

• The struct is implemented in the class shown next…

Page 11: Binary trees

11

IntBinaryTree.hclass IntBinaryTree{public:

struct TreeNode{

int value;TreeNode *left;TreeNode *right;

};

TreeNode *root;void destroySubTree(TreeNode *);void deleteNode(int, TreeNode *&);void makeDeletion(TreeNode *&);void displayInOrder(TreeNode *);void displayPreOrder(TreeNode *);void displayPostOrder(TreeNode *);

Page 12: Binary trees

12

IntBinaryTree.h (continued)

public:IntBinaryTree() // Constructor

{ root = NULL; }~IntBinaryTree() // Destructor

{ destroySubTree(root); }void insertNode(int);bool searchNode(int);void remove(int);void showNodesInOrder(void)

{ displayInOrder(root); }void showNodesPreOrder()

{ displayPreOrder(root); }void showNodesPostOrder()

{ displayPostOrder(root); }};

Page 13: Binary trees

13

Binary Search Tree Operations

• Inserting a Node:First, a new node is allocated and its value member is initialized with the new value.

• The left and right child pointers are set to NULL, because all nodes must be inserted as leaf nodes.

• Next, we determine if the tree is empty. If so, we simply make root point to it, and there is nothing else to be done. But, if there are nodes in the tree, we must find the new node's proper insertion point.

Page 14: Binary trees

14

Binary Search Tree Operations

• If the new value is less than the root node's value, we know it will be inserted somewhere in the left subtree. Otherwise, the value will be inserted into the right subtree.

• We simply traverse the subtree, comparing each node along the way with the new node's value, and deciding if we should continue to the left or the right.

• When we reach a child pointer that is set to NULL, we have found out insertion point.

Page 15: Binary trees

15

The insertNode Member Function

void IntBinaryTree::insertNode(int num){

TreeNode *newNode, // Pointer to a new node *nodePtr; // Pointer to traverse the tree

// Create a new nodenewNode = new TreeNode;newNode->value = num;newNode->left = newNode->right = NULL;

if (!root) // Is the tree empty?root = newNode;

else{

nodePtr = root;

Page 16: Binary trees

16

The insertNode Member Function

while (nodePtr != NULL){

if (num < nodePtr->value){

if (nodePtr->left)nodePtr = nodePtr->left;

else{

nodePtr->left = newNode;break;

}}

Page 17: Binary trees

17

The insertNode Member Function

else if (num > nodePtr->value){

if (nodePtr->right)nodePtr = nodePtr->right;

else{

nodePtr->right = newNode;break;

}}else{

cout << "Duplicate value found in tree.\n";break;

}}

}}

Page 18: Binary trees

18

Program 1// This program builds a binary tree with 5 nodes.

#include <iostream.h>#include "IntBinaryTree.h“

void main(void){

IntBinaryTree tree;

cout << "Inserting nodes. ";tree.insertNode(5);tree.insertNode(8);tree.insertNode(3);tree.insertNode(12);tree.insertNode(9);cout << "Done.\n";

}

Page 19: Binary trees

19

Program 1Figure 5 shows the structure of the binary tree built by the program.

Note: The shape of the tree is determined by the order in which the values are inserted. The root node in the diagram above holds the value 5 because that was the first value inserted.

Page 20: Binary trees

20

Traversing the Tree

• There are three common methods for traversing a binary tree and processing the value of each node: – inorder– preorder– postorder

• Each of these methods is best implemented as a recursive function.

Page 21: Binary trees

21

Inorder Traversal

1. The node’s left subtree is traversed.

2. The node’s data is processed.

3. The node’s right subtree is traversed.

Page 22: Binary trees

22

Preorder Traversal

1. The node’s data is processed.

2. The node’s left subtree is traversed.

3. The node’s right subtree is traversed.

Page 23: Binary trees

23

Postorder Traversal

1. The node’s left subtree is traversed.

2. The node’s right subtree is traversed.

3. The node’s data is processed.

Page 24: Binary trees

24

The displayInOrder Member Function

void IntBinaryTree::displayInOrder(TreeNode *nodePtr){

if (nodePtr){

displayInOrder(nodePtr->left);cout << nodePtr->value << endl;displayInOrder(nodePtr->right);

}}

Page 25: Binary trees

25

The displayPreOrder Member Function

void IntBinaryTree::displayPreOrder(TreeNode *nodePtr){

if (nodePtr){

cout << nodePtr->value << endl;displayPreOrder(nodePtr->left);displayPreOrder(nodePtr->right);

}}

Page 26: Binary trees

26

The displayPostOrder Member Function

void IntBinaryTree::displayPostOrder(TreeNode *nodePtr){

if (nodePtr){

displayPostOrder(nodePtr->left);displayPostOrder(nodePtr->right);cout << nodePtr->value << endl;

}}

Page 27: Binary trees

27

Program 2

// This program builds a binary tree with 5 nodes.// The nodes are displayed with inorder, preorder,// and postorder algorithms.#include <iostream.h>#include "IntBinaryTree.h“

void main(void){

IntBinaryTree tree;

cout << "Inserting nodes.\n";tree.insertNode(5);tree.insertNode(8);tree.insertNode(3);tree.insertNode(12);tree.insertNode(9);

Page 28: Binary trees

28

Program 2 (continued)cout << "Inorder traversal:\n";tree.showNodesInOrder();cout << "\nPreorder traversal:\n";tree.showNodesPreOrder();cout << "\nPostorder traversal:\n";tree.showNodesPostOrder();

}

Page 29: Binary trees

29

Program 2 (continued)Program Output 

Inserting nodes.Inorder traversal:358912 Preorder traversal:538129

Page 30: Binary trees

30

Program 2 (continued)Postorder traversal:3

91285

Page 31: Binary trees

31

Searching the Tree

The IntBinaryTree class has a public member function, SearchNode, which returns true if a value is found in the tree, or false otherwise.

bool IntBinaryTree::searchNode(int num){

TreeNode *nodePtr = root;

while (nodePtr){

if (nodePtr->value == num)return true;

else if (num < nodePtr->value)nodePtr = nodePtr->left;

elsenodePtr = nodePtr->right;

}return false;

}

Page 32: Binary trees

32

Program 3// This program builds a binary tree with 5 nodes.// The SearchNode function determines if the// value 3 is in the tree.#include <iostream.h>#include "IntBinaryTree.h“

void main(void){

IntBinaryTree tree;

cout << "Inserting nodes.\n";tree.insertNode(5);tree.insertNode(8);tree.insertNode(3);tree.insertNode(12);tree.insertNode(9);

Page 33: Binary trees

33

Program 3 (continued)

if (tree.searchNode(3))cout << "3 is found in the tree.\n";

elsecout << "3 was not found in the tree.\n";

}

Program Output Inserting nodes.3 is found in the tree.

Page 34: Binary trees

34

Deleting a Node

• We simply find its parent and set the child pointer that links to it to NULL, and then free the node's memory.

• But what if we want to delete a node that has child nodes? We must delete the node while at the same time preserving the subtrees that the node links to.

Page 35: Binary trees

35

Deleting a Node

• There are two possible situations when we are deleting a non-leaf node:– A) the node has one child, or– B) the node has two children.

Page 36: Binary trees

36

Deleting a Node

Figure 6 illustrates a tree in which we are about to delete a node with one subtree.

Page 37: Binary trees

37

Deleting a Node

Figure 7 shows how we will link the node's subtree with its parent.

Page 38: Binary trees

38

Deleting a Node

The problem is not as easily solved, however, when the node we are about to delete has two subtrees. For example, look at Figure 8.

Page 39: Binary trees

39

Deleting a Node

• We cannot attach both of the node's subtrees to its parent, so there must be an alternative solution.

• One way is to attach the node's right subtree to the parent, and then find a position in the right subtree to attach the left subtree. The result is shown in Figure 9.

Page 40: Binary trees

40

Deleting a Node

Figure 9.

Page 41: Binary trees

41

Deleting a Node

To delete a node from the IntBinaryTree, call the public member function remove. The argument is the value of the node that is to be deleted.

void IntBinaryTree::remove(int num){

deleteNode(num, root);}

The remove member function calls the deleteNode member function. It passes the value of the node to delete, and the root pointer.

Page 42: Binary trees

42

The deleteNode Member Function

void IntBinaryTree::deleteNode(int num, TreeNode *&nodePtr){

if (num < nodePtr->value)deleteNode(num, nodePtr->left);

else if (num > nodePtr->value)deleteNode(num, nodePtr->right);

elsemakeDeletion(nodePtr);

}

Notice the declaration of the nodePtr parameter:

TreeNode *&nodePtr;

nodePtr is not simply a pointer to a TreeNode structure, but a reference to a pointer to a TreeNode structure. Any action performed on nodePtr is actually performed on the argument passed into nodePtr.

Page 43: Binary trees

43

The deleteNode Member Function

elsemakeDeletion(nodePtr);

•The trailing else statement calls the makeDeletion function, passing nodePtr as its argument.

•The makeDeletion function actually deletes the node from the tree, and must reattach the deleted node’s subtrees.

•Therefore, it must have access to the actual pointer in the binary tree to the node that is being deleted.

•This is why the nodePtr parameter in the deleteNode function is a reference.

Page 44: Binary trees

44

The makeDeletion Member Function

void IntBinaryTree::makeDeletion(TreeNode *&nodePtr){

TreeNode *tempNodePtr; // Temporary pointer, used in // reattaching the left subtree.

if (nodePtr == NULL)cout << "Cannot delete empty node.\n";

else if (nodePtr->right == NULL){

tempNodePtr = nodePtr;nodePtr = nodePtr->left; // Reattach the left childdelete tempNodePtr;

}else if (nodePtr->left == NULL){

tempNodePtr = nodePtr;nodePtr = nodePtr->right; // Reattach the right childdelete tempNodePtr;

}

Page 45: Binary trees

45

The makeDeletion Member Function (continued)

// If the node has two children.else{

// Move one node the right.tempNodePtr = nodePtr->right;// Go to the end left node.while (tempNodePtr->left)

tempNodePtr = tempNodePtr->left;// Reattach the left subtree.tempNodePtr->left = nodePtr->left;tempNodePtr = nodePtr;// Reattach the right subtree.nodePtr = nodePtr->right;delete tempNodePtr;

}}

Page 46: Binary trees

46

Program 4// This program builds a binary tree with 5 nodes.// The DeleteNode function is used to remove two// of them.#include <iostream.h>#include "IntBinaryTree.h“

void main(void){

IntBinaryTree tree;

cout << "Inserting nodes.\n";tree.insertNode(5);tree.insertNode(8);tree.insertNode(3);tree.insertNode(12);tree.insertNode(9);

cout << "Here are the values in the tree:\n";tree.showNodesInOrder();

Page 47: Binary trees

47

Program 4 (continued)

cout << "Deleting 8...\n";tree.remove(8);cout << "Deleting 12...\n";tree.remove(12);

cout << "Now, here are the nodes:\n";tree.showNodesInOrder();

}

Page 48: Binary trees

48

Program 4 (continued)

Program Output

 Inserting nodes.Here are the values in the tree:358912Deleting 8...Deleting 12...Now, here are the nodes:359

Page 49: Binary trees

49

Template Considerations for Binary Trees

• When designing your template, remember that any data types stored in the binary tree must support the <, >, and == operators.

• If you use the tree to store class objects, these operators must be overridden.