09.BINARY TREES
SYNTAX
template<class Type>
struct Node
{
Type info;
Node<Type> *lLink;
Node<Type> *rLink;
};

Circle represents a "node"
Each node will have three fields: an information and two pointers (L/R)
A node will have information such as "A"
Nodes can have a pointer to the left (lLink) and a pointer to the right (rLink)
DEFINITIONS
DATA STRUCTURES MAIN OPERATIONS
the three main priority for a programmer when defining data structures are:
insert
delete
search
Binary Trees
A binary tree, T, is either empty or such that
T has a special node called the root node
T has two sets of nodes, TsubL and TsubR (left subtree and right subtree of T)
TsubL and TsubR are binary trees
BINARY TREES, ARRAYS, & LINKED LISTS COMPARISON
when organizing data, a highest priority is to insert, delete, and search data as fast as possible
Arrays: Random access data structure (by index)
+Item search can be fast (mainly if the data is sorted: binary search)
-Item insertion and deletion are time consuming (data shifting)
Linked Lists: Access by pointers
+Faster in insertion and deletion (update some pointers)
-Sequential search (must begin with the first item)
Binary Trees
+More efficient in item insertion, deletion and search
BINARY TREES VISUALIZATION

A is the root of T
B is the left child of A (C is the right child of A)
A is the parent of B and C
TsubL = {B, D, E, G}, TsubR = {C, F, H}, B is the root of TsubL
BINARY TREE W/ ONE NODE

BINARY TREE W/ TWO NODES

BINARY TREE W/ THREE NODES

LEAF
a node in a tree with no left and right children
PARENT
a node U is called the parent of a node V if there is an edge (branch) from U to V
PATH
a path from a node X to a node Y in a binary tree is a sequence of nodes


LEVEL
the level of a node in a binary tree is the number of branches on the path from the root to the node
HEIGHT
the height of a binary tree is the number of nodes on the longest path from the root to a leaf
BINARY TREE TRAVERSAL
the item insertion, deletion, and search operations require that the binary tree be traversed
the traversal must start from the root (as we have a pointer to it)
for each node, we have two choices
visit the node first
visit the subtrees first
the above two choices lead to three different traversals: inorder, preorder, & postorder traversals
INORDER TRAVERSAL
template<class Type>
void inorder(Node<Type>* p){
if (p != NULL){
inorder(p->lLink); //left subtree
cout << p->info << " "; //root
inorder(p->rLink); //right subtree
}
}
the binary tree is traversed as follows:
traverse the left subtree (recursive call)
visit the current root
traverse the right subtree (recursive call)

PREORDER TRAVERSAL
template<class Type>
void preorder(Node<Type>* p){
if (p != NULL){
cout << p->info << " "; //root
preorder(p->lLink); //left subtree
preorder(p->rLink); //right subtree
}
}
the binary tree is traversed as follows:
visit the current root
traverse the left subtree (recursive call)
traverse the right subtree (recursive call)

POSTORDER TRAVERSAL
template<class Type>
void postorder(Node<Type>* p){
if (p != NULL){
postorder(p->lLink); //left subtree
postorder(p->rLink); //right subtree
cout << p->info << " "; //root
}
}
the binary tree is traversed as follows:
traverse the left subtree (recursive call)
traverse the right subtree (recursive call)
visit the currrent root

BINARY SEARCH TREE T
T is either empty or:
T has a special node called the root node
T has two sets of nodes, TsubL and TsubR, called left subtree and right subtree of T
The value in the root node is larger than every value in the left subtree and smaller than every value in the right subtree
TsubL and TsubR are binary search trees
BINARY SEARCH TREES OPERATIONS (FUNCTIONS)
determine whether the binary tree is empty
find the height of the binary tree
find the number of nodes in the binary tree
find the number of leaves in the binary tree
traverse the binary tree
IMPLEMENTATION
UML
VISUALIZATION
SOURCE
HEADER FILE: binaryTree.h
The data members of the class are divided into public, protected, and private. All the public functions have no parameters. The parameters are specified in the private functions.
the public members are to be used outside the class to handle the binary tree as an ADT
the protected member(the pointer to the root of the tree) is to be used to derive special binary trees
the private members are used to implement the public functions. the user of the class doesn't need to access them
/*################################################
# Name: Stephen Razon
# Student ID:
# Date: 081253DEC24
# Filename: binaryTree.h
# Dependency: N/A
################################################*/
template<class Type>
struct Node
{
Type info;
Node<Type>* lLink;
Node<Type>* rLink;
};
template<class Type>
class BinaryTree
{
protected:
Node<Type>* root;
//these functions are used to assist in the implementation of the public functions
private:
void destroy(Node<Type>*&);
void inorder(Node<Type>*);
void preorder(Node<Type>*);
void postorder(Node<Type>*);
int height(Node<Type>*);
int max(int, int);
int nodeCount(Node<Type>*);
int leavesCount(Node<Type>*);
//these functions doesn't have parameter to prevent the root from being manipulated
public:
BinaryTree();
bool isEmpty();
void inorderTraversal();
void preorderTraversal();
void postorderTraversal();
int treeHeight();
int treeNodeCount();
int treeLeavesCount();
void destroyTree();
~BinaryTree();
};
//inheritance
template<class Type>
class BinarySearchTree : public
BinaryTree<Type>
{
private:
void deleteFromTree(Node<Type>*&);
public:
bool search(const Type&);
void insert(const Type&);
void deleteNode(const Type&);
};
HEADER FILE: binaryTreeImplementation.h
/*################################################
# Name: Stephen Razon
# Student ID:
# Date: 081253DEC24
# Filename: binaryTreeImplementation.h
# Dependency: binaryTree.h
################################################*/
#include "binaryTree.h"
template<class Type>
BinaryTree<Type>::BinaryTree(){ //constructor
root = NULL;
}
template<class Type>
bool BinaryTree<Type>::isEmpty(){
return(root == NULL);
}
template<class Type>
void BinaryTree<Type>::inorderTraversal(){ //this is a public function and calls the private function
inorder(root);
}
template<class Type>
void BinaryTree<Type>::inorder(Node<Type>* p){
if (p != NULL){
inorder(p->lLink);
cout << p->info << " ";
inorder(p->rLink);
}
}
template<class Type>
void BinaryTree<Type>::preorderTraversal(Node<Type>* p){
preorder(root);
}
template<class Type>
void BinaryTree<Type>::preorder(Node<Type>* p){
if (p != NULL){
cout << p->info << " "; //root
preorder(p->lLink); //left subtree
preorder(p->rLink); //right subtree
}
}
template<class Type>
void BinaryTree<Type>::postorderTraversal(Node<Type>* p){
postorder(root);
}
template<class Type>
void BinaryTree<Type>::postorder(Node<Type>* p){
if (p != NULL){
postorder(p->lLink); //left subtree
postorder(p->rLink); //right subtree
cout << p->info << " "; //root
}
}
template<class Type>
int BinaryTree<Type>::treeHeight(){
return height(root);
}
template<class Type>
int BinaryTree<Type>::height(Node<Type>* p){
if (p == NULL)
return 0;
else
//1 is the root node + the no of nodes in the left subtree + the no of nodes in the right subtree
return 1 + max(height(p->lLink), height(p->rLink));
}
template<class Type>
Type BinaryTree<Type>::max(Type x, Type y){
if (x >= y)
return x;
else
return y;
}
template<class Type>
int BinaryTree<Type>::treeNodeCount(){
return nodeCount(root);
}
template<class Type>
int BinaryTree<Type>::nodeCount(Node<Type>* p){
if (p == NULL)
return 0;
else
//1 is the root node + the no of nodes in the left subtree + the no of nodes in the right subtree
return 1 + nodeCount(p->lLink) + nodeCount(p->rLink);
}
template<class Type>
int BinaryTree<Type>::treeLeavesCount(){
return leavesCount(root);
}
/*leavesCount
Basic step:
If the tree is empty, return 0
If the tree contains only one node, return 1
Recursive step:
Return the number of leaves of the left subtree + the number of leaves of the right subtree.
*/
template<class Type>
int BinaryTree<Type>::leavesCount(Node<Type>* p){
if (p == NULL)
return 0;
if (p->lLink == NULL && p->rLink == NULL)
return 1;
else
return leavesCount(p->lLink) + leavesCount(p->rLink);
}
template<class Type>
void BinaryTree<Type>::destroyTree()
{
destroy(root);
}
template<class Type>
void BinaryTree<Type>::destroy(Node<Type>*& p){
if (p != NULL){
destroy(p->lLink);
destroy(p->rLink);
delete p;
p = NULL;
}
}
template<class Type>
BinaryTree<Type>::~BinaryTree(){
destroy(root);
}
template<class Type>
bool BinarySearchTree<Type>::search(const Type& x){
Node<Type>* current;
bool found = false;
if (this->root == NULL)
cout << "Empty tree!" << endl;
else{
current = this->root;
while (current != NULL && !found){
if (current->info == x)
found = true;
else if (current->info > x)
current = current->lLink;
else
current = current->rLink;
}
}
return found;
}
template<class Type>
void BinarySearchTree<Type>::insert(const Type& x){
Node<Type>* current, *prevCurrent=NULL, *newNode;
newNode = new Node<Type>;
assert(newNode != NULL);
newNode->info = x; newNode->lLink = NULL; newNode->rLink = NULL;
if (this->root == NULL)
this->root = newNode;
else{
current = this->root;
while (current != NULL){
prevCurrent = current;
if (current->info == x){
cout << "Item is already in the list!" << endl;
return;
}
else if (current->info > x)
current = current->lLink;
else
current = current->rLink;
}
if (prevCurrent->info > x)
prevCurrent->lLink = newNode;
else
prevCurrent->rLink = newNode;
}
}
template<class Type>
void BinarySearchTree<Type>::deleteFromTree(Node<Type>*& p){
Node<Type>* current, *prevCurrent, *temp;
if (p == NULL)
cout << "The node to be deleted is NULL!" << endl;
else if (p->llink == NULL && p->rlink == NULL) {//p points to a leaf
temp = p;
p = NULL;
delete temp;
}
else if (p->llink == NULL) { //p points to a node with only a right child
temp = p;
p = temp->rlink;
delete temp;
}
else if (p->rlink == NULL) { //p points to a node with only a left child
temp = p;
p = temp->llink;
delete temp;
}
else { //p points to a node with two children
current = p->llink;
prevCurrent = NULL;
while (current->rlink != NULL){
prevCurrent = current;
current = current->rlink;
}
p->info = current->info;
if (prevCurrent == NULL) //current did not move, current = p->llink, adjust p
p->llink = current->llink;
else
prevCurrent->rlink = current->llink;
delete current;
}
}
//************************** deleteNode **************************
template<class Type>
void BinarySearchTree<Type>::deleteNode(const Type& x){
Node<Type>* current;
Node<Type>* prevCurrent;
bool found = false;
if (this->root == NULL)
cout << "Cannot delete from an empty tree!" << endl;
else{
current = this->root;
prevCurrent = this->root;
while (current != NULL && !found){
if (current->info == x)
found = true;
else{
prevCurrent = current;
if (current->info > x)
current = current->llink;
else
current = current->rlink;
}
}
if (current == NULL)
cout << "The item is not in the tree!" << endl;
else if (found){
if (current == this->root)
deleteFromTree(this->root);
else
if (prevCurrent->info > x)
deleteFromTree(prevCurrent->llink);
else
deleteFromTree(prevCurrent->rlink);
}
}
}







#include<iostream>
using namespace std;
#include"BinarySearchTree.h"
void main()
{
BinarySearchTree<int> bst;
bst.insert(3);
bst.insert(5);
bst.insert(2);
bst.insert(-1);
bst.insert(4);
bst.insert(6);
bst.insert(-3);
bst.insert(1);
bst.insert(0);
//bst.inorderTraversal();
bst.postorderTraversal();
bst.deleteNode(-3);
cout << "\n";
bst.postorderTraversal();
//bst.preorderTraversal();
cout << "\nNumber of leaves: "<<bst.treeLeavesCount() << endl;;
}
Last updated