Level Order Traversal is a technique used to traverse a Tree where all nodes at the same level are visited entirely before moving to the next level.
The level order traversal of this tree will be as follows:
1
2 3 5
6 8 7 9 10
11 12 13 14
Working of Level Order Traversal
Level order traversal involves visiting all nodes at a lower level before proceeding to any nodes at a higher level. This can be achieved through two main approaches:
- Naive method: Determining the height of the tree and traversing each level sequentially, printing the nodes of each level.
- Efficient method: Utilizing a queue data structure to traverse the tree level by level, ensuring nodes at the same level are visited before moving to the next level.
Level Order Traversal Using Recursion
- Finding Tree Height: Initially, find the height of the tree using a recursive function or any suitable method. This provides the total number of levels in the tree.
- Recursive Traversal with Level Tracking: Implement a recursive function that traverses the tree, maintaining the current height or level as a parameter.
- Printing Nodes at Target Level: Within the recursive function, whenever the current level matches the target level for which nodes need to be printed, print the value of the node.
- Recursion Termination: Ensure that the recursive function terminates appropriately when it reaches the end of the tree or the desired level.
Code Implementation in C++
#include <iostream>
using namespace std;
// A binary tree node has data,
// pointer to left child
// and a pointer to right child
class TreeNode {
public:
int data;
TreeNode* left, * right;
};
// Function prototypes
void printCurrentLevelNodes(TreeNode* root, int level);
int calculateTreeHeight(TreeNode* node);
TreeNode* createNewNode(int data);
// Function to print level order traversal of a tree
void performLevelOrderTraversal(TreeNode* root)
{
// Base case: If the tree is empty
if (root == NULL)
return;
// Get the height of the tree
int height = calculateTreeHeight(root);
// Iterate over each level
for (int i = 1; i <= height; i++) {
// Print nodes at the current level
printCurrentLevelNodes(root, i);
}
}
// Print nodes at a current level
void printCurrentLevelNodes(TreeNode* root, int level)
{
if (root == NULL)
return;
if (level == 1)
cout << root->data << " ";
else if (level > 1) {
printCurrentLevelNodes(root->left, level - 1);
printCurrentLevelNodes(root->right, level - 1);
}
}
// Determine the "height" of a tree, which represents the count of nodes // on the path which is longest from the root node to the deepest leaf node.
int calculateTreeHeight(TreeNode* node)
{
if (node == NULL)
return 0;
else {
// Compute the height of each subtree
int leftHeight = calculateTreeHeight(node->left);
int rightHeight = calculateTreeHeight(node->right);
// Use the larger one
if (leftHeight > rightHeight) {
return (leftHeight + 1);
}
else {
return (rightHeight + 1);
}
}
}
// This function creates a new node with the specified data and initializes // its left and right pointers to NULL.
TreeNode* createNewNode(int data)
{
TreeNode* newNode = new TreeNode();
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
// Driver code
int main()
{
// Create a binary tree
TreeNode* root = createNewNode(1);
root->left = createNewNode(2);
root->right = createNewNode(3);
root->left->left = createNewNode(4);
root->left->right = createNewNode(5);
// Get the level order traversal of the given tree
cout << "Level Order traversal: ";
performLevelOrderTraversal(root);
return 0;
}
Code Implementation in Java
class TreeNode {
int data;
TreeNode left, right;
public TreeNode(int data) {
this.data = data;
this.left = null;
this.right = null;
}
}
public class LevelOrderTraversal {
// Function to print nodes at the current level
static void printCurrentLevelNodes(TreeNode root, int level) {
if (root == null)
return;
if (level == 1)
System.out.print(root.data + " ");
else if (level > 1) {
printCurrentLevelNodes(root.left, level - 1);
printCurrentLevelNodes(root.right, level - 1);
}
}
// Function to find the height of the givtree
static int calculateTreeHeight(TreeNode node) {
if (node == null)
return 0;
else {
// Find the height of the left and right subtrees
int leftHeight = calculateTreeHeight(node.left);
int rightHeight = calculateTreeHeight(node.right);
// Return the maximum height
return Math.max(leftHeight, rightHeight) + 1;
}
}
// Function to have a level order traversal of the binary tree
static void performLevelOrderTraversal(TreeNode root) {
// Get the height of the tree
int height = calculateTreeHeight(root);
// Iterate over each level and print the nodes
for (int i = 1; i <= height; i++) {
printCurrentLevelNodes(root, i);
}
}
// Driver code
public static void main(String[] args) {
// Create a binary tree
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
// Get the level order traversal of the given tree
System.out.println("Level Order traversal: ");
performLevelOrderTraversal(root);
}
}
Code Implementation in Python
class TreeNode:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
# Function to print nodes at the current level
def printCurrentLevelNodes(root, level):
if root is None:
return
if level == 1:
print(root.data, end=" ")
elif level > 1:
printCurrentLevelNodes(root.left, level - 1)
printCurrentLevelNodes(root.right, level - 1)
def calculateTreeHeight(node):
if node is None:
return 0
else:
# Calculate the height of the left and right subtrees
leftHeight = calculateTreeHeight(node.left)
rightHeight = calculateTreeHeight(node.right)
# Return the maximum height
return max(leftHeight, rightHeight) + 1
# Function to find level order traversal of the binary tree
def performLevelOrderTraversal(root):
# Get the height of the tree
height = calculateTreeHeight(root)
# Iterate over each level and print the nodes
for i in range(1, height + 1):
printCurrentLevelNodes(root, i)
# Driver code
if __name__ == "__main__":
# Create a binary tree
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)
# Get the level order traversal of the given tree
print("Level Order traversal: ")
performLevelOrderTraversal(root)
Output:
Level Order traversal: 1 2 3 4 5
Complexity Analysis
Time Complexity:
The level order traversal algorithm has a time complexity of O(N), where N denotes the count of total number of nodes in the skewed tree.
Space Complexity:
As for space complexity, it’s O(1) if we only consider the variables used within the function. However, if we consider the recursion stack, then it can be O(N) in the worst case, particularly for skewed trees.
Level Order Traversal Using Queue
Level order traversal follows the principle of visiting nodes in lower levels before higher ones, similar to a queue. Nodes of lower levels are enqueued first, and when visiting a node, it’s dequeued and its children are enqueued. This guarantees traversal from lower to higher levels orderly.
Code Implementation in C++
#include <iostream>
#include <queue>
using namespace std;
struct Node {
int data;
Node* left;
Node* right;
};
Node* createNode(int data) {
Node* newNode = new Node();
if (!newNode) {
cout << "Memory error\n";
return nullptr;
}
newNode->data = data;
newNode->left = newNode->right = nullptr;
return newNode;
}
void levelOrderTraversal(Node* root) {
if (root == nullptr)
return;
queue<Node*> q;
q.push(root);
while (!q.empty()) {
Node* current = q.front();
q.pop();
cout << current->data << " ";
if (current->left)
q.push(current->left);
if (current->right)
q.push(current->right);
}
}
int main() {
// Create a binary tree
Node* root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
root->right->left = createNode(6);
root->right->right = createNode(7);
// Perform level order traversal
cout << "Level Order Traversal: ";
levelOrderTraversal(root);
return 0;
}
Code Implementation in Java
import java.util.LinkedList;
import java.util.Queue;
class Node {
int data;
Node left, right;
public Node(int item) {
data = item;
left = right = null;
}
}
public class LevelOrderTraversal {
Node root;
void levelOrderTraversal() {
if (root == null)
return;
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
Node current = queue.poll();
System.out.print(current.data + " ");
if (current.left != null)
queue.add(current.left);
if (current.right != null)
queue.add(current.right);
}
}
public static void main(String args[]) {
LevelOrderTraversal tree = new LevelOrderTraversal();
tree.root = new Node(1);
tree.root.left = new Node(2);
tree.root.right = new Node(3);
tree.root.left.left = new Node(4);
tree.root.left.right = new Node(5);
tree.root.right.left = new Node(6);
tree.root.right.right = new Node(7);
System.out.print("Level Order Traversal: ");
tree.levelOrderTraversal();
}
}
Code Implementation in Python
class Node:
def __init__(self, key):
self.data = key
self.left = None
self.right = None
def levelOrderTraversal(root):
if root is None:
return
queue = []
queue.append(root)
while queue:
current = queue.pop(0)
print(current.data, end=" ")
if current.left:
queue.append(current.left)
if current.right:
queue.append(current.right)
# Create a binary tree
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
root.right.left = Node(6)
root.right.right = Node(7)
# Perform level order traversal
print("Level Order Traversal:", end=" ")
levelOrderTraversal(root)
Output:
Level Order Traversal: 1 2 3 4 5 6 7
Complexity Analysis
Time Complexity:
The algorithm’s time complexity is O(N), where N denotes the number of nodes present in the binary tree.
Space Complexity:
The space complexity is O(N) due to the queue used for level order traversal, which can hold up to N nodes at its maximum capacity.
Conclusion
- Level Order Traversal: It’s a technique to traverse a tree where all nodes at the same level are visited before moving to the next level.
- Working Principle: Nodes at lower levels are visited entirely before proceeding to any nodes at higher levels.
- Two Approaches: It can be implemented using either a naive method or an efficient method utilizing a queue.
- Naive Method: Involves determining the height of the tree and sequentially traversing each level, printing the nodes of each level.
- Efficient Method: Utilizes a queue data structure to traverse the tree level by level, ensuring nodes at the same level are visited before moving to the next level.