Binary Trees - 1
Binary Trees - 1
What is A Tree?
● A tree is a data structure similar to a linked list but instead of each node
pointing simply to the next node in a linear fashion, each node points to
several nodes.
● A tree is an example of a non- linear data structure.
● A tree structure is a way of representing the hierarchical nature of a
structure in a graphical form.
Terminology Of Trees
● The root of a tree is the node with no parents. There can be at most one root
node in a tree (node A in the above example).
1
● An edge refers to the link from a parent to a child (all links in the figure).
● A node with no children is called a leaf node (E, J, K, H, and I).
● The children nodes of the same parent are called siblings (B, C, D are
siblings of parent A and E, F are siblings of parent B).
● The set of all nodes at a given depth is called the level of the tree (B, C, and
D are the same level). The root node is at level zero.
● The depth of a node is the length of the path from the root to the node
(depth of G is 2, A -> C –> G).
● The height of a node is the length of the path from that node to the deepest
node.
● The height of a tree is the length of the path from the root to the deepest
node in the tree.
● A (rooted) tree with only one node (the root) has a height of zero.
Binary Trees
● A generic tree with at most two child nodes for each parent node is known as
a binary tree.
● A binary tree is made of nodes that constitute a left pointer, a right pointer,
and a data element. The root pointer is the topmost node in the tree.
● The left and right pointers recursively point to smaller subtrees on either
side.
● An empty tree is also a valid binary tree.
● A formal definition is: A binary tree is either empty (represented by a None
pointer), or is made of a single node, where the left and right pointers
(recursive definition ahead) each point to a binary tree.
2
Types of binary trees:
Full binary trees: A binary tree in which every node has 0 or 2 children is
termed as a full binary tree.
Complete binary tree: A complete binary tree has all the levels filled except for
the last level, which has all its nodes as much as to the left.
Perfect binary tree: A binary tree is termed perfect when all its internal nodes
have two children along with the leaf nodes that are at the same level.
3
A degenerate tree: In a degenerate tree, each internal node has only one child.
4
The tree shown above is degenerate. These trees are very similar to linked-lists.
Balanced binary tree: A binary tree in which the difference between the depth
of the two subtrees of every node is at most one is called a balanced binary tree.
5
Binary tree representation:
Binary trees can be represented in two ways:
Sequential representation
● This is the most straightforward technique to store a tree data structure. An
array is used to store the tree nodes.
● The number of nodes in a tree defines the size of the array.
● The root node of the tree is held at the first index in the array.
● In general, if a node is stored at the ith location, then its left and right child
are kept at (2i)th and (2i+1)th locations in the array, respectively.
6
The array representation of the above binary tree is as follows:
As discussed above, we see that the left and right child of each node is stored at
locations 2*(nodePosition) and 2*(nodePosition)+1, respectively.
7
For Example, The location of node 3 in the array is 3. So its left child will be placed
at 2*3 = 6. Its right child will be at the location 2*3 +1 = 7. As we can see in the
array, children of 3, which are 6 and 7, are placed at locations 6 and 7 in the array.
Note: The sequential representation of the tree is not preferred due to the massive
amount of memory consumption by the array.
As shown in the above representation, each linked list node has three components:
8
class BinaryTreeNode:
def __init__(self, data):
self.left = None #To store data
self.right = None #For storing the reference to left pointer
self.data = data #For storing the reference to right pointer
def printTree(root):
root == None: #Empty tree
return
print(root.data, end ":") #Print root data
if root.left != None:
print("L", root.left.data, end=",") #Print left child
if root.right != None:
print("R", root.right.data, end="") #Print right child
Print #New line
9
printTree(root.left) #Recursive call to print left subtree
printTree(root.right) #Recursive call to print right subtree
def treeInput():
rootData = int(input())
if rootData == -1: #Leaf Node is denoted by -1
return None
Count nodes
● Unlike the Generic trees, where we need to traverse the children vector of
each node, in binary trees, we just have at most left and right children for
each node.
● Here, we just need to recursively call on the right and left subtrees
independently with the condition that the node pointer is not None.
● Follow the comments in the upcoming code for better understanding:
def count_nodes(node):
if node is None: #Check if root node is None
return 0
10
return 1 + count_nodes(node.left) + count_nodes(node.right)
#Recursively count number of nodes in left and right subtree and add
❖ Preorder traversal: 1, 2, 4, 5, 3, 6, 7
❖ Postorder traversal: 4, 5, 2, 6, 7, 3, 1
❖ Inorder traversal: 4, 2, 5, 1, 6, 3, 7
11
print(root.val)# Then print the data of the node
printInorder(root.right) # Now recur on right child
Now, from this inorder traversal code, try to code preorder and postorder traversal
yourselves. If you get stuck, refer to the solution tab for the same.
def findMaximum(root):
# Base case
if (root == None):
return float('-inf') #**
12
Note**: In python, float values can be used to represent an infinite integer. One can
use float('-inf') as an integer to represent it as “Negative” infinity or the smallest
possible integer.
13