Binary Search Tree
Binary Search Tree
Binary Search Tree is a node-based binary tree data structure which has the
following properties:
The left subtree of a node contains only nodes with keys lesser than the
node’s key.
The right subtree of a node contains only nodes with keys greater than the
node’s key.
The left and right subtree each must also be a binary search tree.
Basic :
Searching a key
To search a given key in Binary Search Tree, we first compare it with root, if the key
is present at root, we return root. If key is greater than root’s key, we recur for right
subtree of root node. Otherwise we recur for left subtree.
// A utility function to search a given key in BST
public Node search(Node root, int key)
{
// Base Cases: root is null or key is present at root
if (root==null || root.key==key)
return root;
// val is greater than root's key
if (root.key > key)
return search(root.left, key);
// val is less than root's key
return search(root.right, key);
}
Illustration to search 6 in below tree:
1. Start from root.
2. Compare the inserting element with root, if less than root, then recurse for left,
else recurse for right.
3. If element to search is found anywhere, return true, else return false.
Insertion of a key
A new key is always inserted at leaf. We start searching a key from root till we hit a
leaf node. Once a leaf node is found, the new node is added as a child of the leaf
node.
100 100
/ \ Insert 40 / \
20 500 ---------> 20 500
/ \ / \
10 30 10 30
\
40
Output:
20
30
40
50
60
70
80
Illustration to insert 2 in below tree:
1. Start from root.
2. Compare the inserting element with root, if less than root, then recurse for left,
else recurse for right.
3. After reaching end,just insert that node at left(if less than current) else right.
Time Complexity: The worst case time complexity of search and insert operations is
O(h) where h is height of Binary Search Tree. In worst case, we may have to travel
from root to the deepest leaf node. The height of a skewed tree may become n and
the time complexity of search and insert operation may become O(n).
Binary Search Tree | Set 2 (Delete)
We have discussed BST search and insert operations. In this post, delete operation is
discussed. When we delete a node, three possibilities arise.
1) Node to be deleted is leaf: Simply remove from the tree.
50 50
/ \ delete(20) / \
30 70 ---------> 30 70
/ \ / \ \ / \
20 40 60 80 40 60 80
2) Node to be deleted has only one child: Copy the child to the node and delete the
child
50 50
/ \ delete(30) / \
30 70 ---------> 40 70
\ / \ / \
40 60 80 60 80
3) Node to be deleted has two children: Find inorder successor of the node. Copy
contents of the inorder successor to the node and delete the inorder successor. Note
that inorder predecessor can also be used.
50 60
/ \ delete(50) / \
40 70 ---------> 40 70
/ \ \
60 80 80
The important thing to note is, inorder successor is needed only when right child is
not empty. In this particular case, inorder successor can be obtained by finding the
minimum value in right child of the node.
// Java program to demonstrate delete operation in binary search tree
class BinarySearchTree
{
/* Class containing left and right child of current node and key
value*/
class Node
{
int key;
Node left, right;
public Node(int item)
{
key = item;
left = right = null;
}
}
// Root of BST
Node root;
// Constructor
BinarySearchTree()
{
root = null;
}
// This method mainly calls deleteRec()
void deleteKey(int key)
{
root = deleteRec(root, key);
}
/* A recursive function to insert a new key in BST */
Node deleteRec(Node root, int key)
{
/* Base Case: If the tree is empty */
if (root == null) return root;
/* Otherwise, recur down the tree */
if (key < root.key)
root.left = deleteRec(root.left, key);
else if (key > root.key)
root.right = deleteRec(root.right, key);
// if key is same as root's key, then This is the node
// to be deleted
else
{
// node with only one child or no child
if (root.left == null)
return root.right;
else if (root.right == null)
return root.left;
// node with two children: Get the inorder successor (smallest
// in the right subtree)
root.key = minValue(root.right);
// Delete the inorder successor
root.right = deleteRec(root.right, root.key);
}
return root;
}
int minValue(Node root)
{
int minv = root.key;
while (root.left != null)
{
minv = root.left.key;
root = root.left;
}
return minv;
}
// This method mainly calls insertRec()
void insert(int key)
{
root = insertRec(root, key);
}
/* A recursive function to insert a new key in BST */
Node insertRec(Node root, int key)
{
/* If the tree is empty, return a new node */
if (root == null)
{
root = new Node(key);
return root;
}
/* Otherwise, recur down the tree */
if (key < root.key)
root.left = insertRec(root.left, key);
else if (key > root.key)
root.right = insertRec(root.right, key);
/* return the (unchanged) node pointer */
return root;
}
// This method mainly calls InorderRec()
void inorder()
{
inorderRec(root);
}
// A utility function to do inorder traversal of BST
void inorderRec(Node root)
{
if (root != null)
{
inorderRec(root.left);
System.out.print(root.key + " ");
inorderRec(root.right);
}
}
// Driver Program to test above functions
public static void main(String[] args)
{
BinarySearchTree tree = new BinarySearchTree();
/* Let us create following BST
50
/ \
30 70
/ \ / \
20 40 60 80 */
tree.insert(50);
tree.insert(30);
tree.insert(20);
tree.insert(40);
tree.insert(70);
tree.insert(60);
tree.insert(80);
System.out.println("Inorder traversal of the given tree");
tree.inorder();
System.out.println("\nDelete 20");
tree.deleteKey(20);
System.out.println("Inorder traversal of the modified tree");
tree.inorder();
System.out.println("\nDelete 30");
tree.deleteKey(30);
System.out.println("Inorder traversal of the modified tree");
tree.inorder();
System.out.println("\nDelete 50");
tree.deleteKey(50);
System.out.println("Inorder traversal of the modified tree");
tree.inorder();
}
}
Output:
Inorder traversal of the given tree
20 30 40 50 60 70 80
Delete 20
Inorder traversal of the modified tree
30 40 50 60 70 80
Delete 30
Inorder traversal of the modified tree
40 50 60 70 80
Delete 50
Inorder traversal of the modified tree
40 60 70 80
Illustration:
Time Complexity: The worst case time complexity of delete operation is O(h) where
h is height of Binary Search Tree. In worst case, we may have to travel from root to
the deepest leaf node. The height of a skewed tree may become n and the time
complexity of delete operation may become O(n)
1. We can get all keys in sorted order by just doing Inorder Traversal of BST. This
is not a natural operation in Hash Tables and requires extra efforts.
2. Doing order statistics, finding closest lower and greater elements, doing
range queries are easy to do with BSTs. Like sorting, these operations are not a
natural operation with Hash Tables.
3. BSTs are easy to implement compared to hashing, we can easily implement
our own customized BST. To implement Hashing, we generally rely on libraries
provided by programming languages.
4. With Self-Balancing BSTs, all operations are guaranteed to work in O(Logn)
time. But with Hashing, Θ(1) is average time and some particular operations
may be costly, especially when table resizing happens.
Output:
Inorder traversal of Binary Tree:
1 5 7 10 40 50
Time Complexity: O(n)
Construct BST from given preorder
traversal | Set 2
Given preorder traversal of a binary search tree, construct the BST.
For example, if the given traversal is {10, 5, 1, 7, 40, 50}, then the output should be
root of following tree.
10
/ \
5 40
/ \ \
1 7 50
We have discussed O(n^2) and O(n) recursive solutions in the previous post.
Following is a stack based iterative solution that works in O(n) time.
Output:
Inorder traversal of the constructed tree is
1 5 7 10 40 50
Time Complexity: O(n). The complexity looks more from first look. If we take a closer
look, we can observe that every item is pushed and popped only once. So at most 2n
push/pop operations are performed in the main loops of constructTree(). Therefore,
time complexity is O(n).
Examples:
Input: Linked List 1->2->3
Output: A Balanced BST
2
/ \
1 3
Method 2 (Tricky)
Method 1 constructs the tree from root to leaves. In this method, we construct from
leaves to root. The idea is to insert nodes in BST in the same order as they appear in
Linked List so that the tree can be constructed in O(n) time complexity. We first
count the number of nodes in the given Linked List. Let the count be n. After
counting nodes, we take left n/2 nodes and recursively construct the left subtree.
After left subtree is constructed, we allocate memory for root and link the left
subtree with root. Finally, we recursively construct the right subtree and link it with
root.
While constructing the BST, we also keep moving the list head pointer to next so that
we have the appropriate pointer in each recursive call.
class LinkedList {
/* head node of link list */
static LNode head;
/* Link list Node */
class LNode
{
int data;
LNode next, prev;
LNode(int d)
{
data = d;
next = prev = null;
}
}
/* A Binary Tree Node */
class TNode
{
int data;
TNode left, right;
TNode(int d)
{
data = d;
left = right = null;
}
}
/* This function counts the number of nodes in Linked List
and then calls sortedListToBSTRecur() to construct BST */
TNode sortedListToBST()
{
/*Count the number of nodes in Linked List */
int n = countNodes(head);
/* Construct BST */
return sortedListToBSTRecur(n);
}
/* The main function that constructs balanced BST and
returns root of it.
n --> No. of nodes in the Doubly Linked List */
TNode sortedListToBSTRecur(int n)
{
/* Base Case */
if (n <= 0)
return null;
/* Recursively construct the left subtree */
TNode left = sortedListToBSTRecur(n / 2);
/* head_ref now refers to middle node,
make middle node as root of BST*/
TNode root = new TNode(head.data);
// Set pointer to left subtree
root.left = left;
/* Change head pointer of Linked List for parent
recursive calls */
head = head.next;
/* Recursively construct the right subtree and link it
with root. The number of nodes in right subtree is
total nodes - nodes in left subtree - 1 (for root) */
root.right = sortedListToBSTRecur(n - n / 2 - 1);
return root;
}
/* UTILITY FUNCTIONS */
/* A utility function that returns count of nodes in a
given Linked List */
int countNodes(LNode head)
{
int count = 0;
LNode temp = head;
while (temp != null)
{
temp = temp.next;
count++;
}
return count;
}
/* Function to insert a node at the beginging of
the Doubly Linked List */
void push(int new_data)
{
/* allocate node */
LNode new_node = new LNode(new_data);
/* since we are adding at the begining,
prev is always NULL */
new_node.prev = null;
/* link the old list off the new node */
new_node.next = head;
/* change prev of head node to new node */
if (head != null)
head.prev = new_node;
/* move the head to point to the new node */
head = new_node;
}
/* Function to print nodes in a given linked list */
void printList(LNode node)
{
while (node != null)
{
System.out.print(node.data + " ");
node = node.next;
}
}
/* A utility function to print preorder traversal of BST */
void preOrder(TNode node)
{
if (node == null)
return;
System.out.print(node.data + " ");
preOrder(node.left);
preOrder(node.right);
}
/* Driver program to test above functions */
public static void main(String[] args) {
LinkedList llist = new LinkedList();
/* Let us create a sorted linked list to test the functions
Created linked list will be 7->6->5->4->3->2->1 */
llist.push(7);
llist.push(6);
llist.push(5);
llist.push(4);
llist.push(3);
llist.push(2);
llist.push(1);
System.out.println("Given Linked List ");
llist.printList(head);
/* Convert List to BST */
TNode root = llist.sortedListToBST();
System.out.println("");
System.out.println("Pre-Order Traversal of constructed BST ");
llist.preOrder(root);
}
}
Output:
Given Linked List 1 2 3 4 5 6 7
PreOrder Traversal of constructed BST 4 2 1 3 6 5 7
Time Complexity: O(n)
Algorithm
In the previous post, we discussed construction of BST from sorted Linked List.
Constructing from sorted array in O(n) time is simpler as we can get the middle
element in O(1) time. Following is a simple algorithm where we first find the middle
node of list and make it root of the tree to be constructed.
Output:
Preorder traversal of constructed BST
4213657
Time Complexity: O(n)
Following is the recurrance relation for sortedArrayToBST().
T(n) = 2T(n/2) + C
T(n) --> Time taken for an array of size n
C --> Constant (Finding middle of array and linking root to left
and right subtrees take constant time)
For the above tree, we start with 20, then we move left 8, we keep on moving to left
until we see NULL. Since left of 4 is NULL, 4 is the node with minimum value.
LCA of 10 and 14 is 12
LCA of 14 and 8 is 8
LCA of 10 and 22 is 20
Following is definition of LCA from Wikipedia:
Let T be a rooted tree. The lowest common ancestor between two nodes n1 and n2
is defined as the lowest node in T that has both n1 and n2 as descendants (where we
allow a node to be a descendant of itself).
The LCA of n1 and n2 in T is the shared ancestor of n1 and n2 that is located farthest
from the root. Computation of lowest common ancestors may be useful, for
instance, as part of a procedure for determining the distance between pairs of nodes
in a tree: the distance from n1 to n2 can be computed as the distance from the root
to n1, plus the distance from the root to n2, minus twice the distance from the root
to their lowest common ancestor. (Source Wiki)
If we are given a BST where every node has parent pointer, then LCA can be easily
determined by traversing up using parent pointer and printing the first intersecting
node.
We can solve this problem using BST properties. We can recursively traverse the BST
from root. The main idea of the solution is, while traversing from top to bottom, the
first node n we encounter with value between n1 and n2, i.e., n1 < n < n2 or same as
one of the n1 or n2, is LCA of n1 and n2 (assuming that n1 < n2). So just recursively
traverse the BST in, if node’s value is greater than both n1 and n2 then our LCA lies in
left side of the node, if it’s is smaller than both n1 and n2, then LCA lies on right side.
Otherwise root is LCA (assuming that both n1 and n2 are present in BST)
// Recursive Java program to print lca of two nodes
// A binary tree node
class Node
{
int data;
Node left, right;
Node(int item)
{
data = item;
left = right = null;
}
}
class BinaryTree
{
Node root;
/* Function to find LCA of n1 and n2. The function assumes that both
n1 and n2 are present in BST */
Node lca(Node node, int n1, int n2)
{
if (node == null)
return null;
// If both n1 and n2 are smaller than root, then LCA lies in left
if (node.data > n1 && node.data > n2)
return lca(node.left, n1, n2);
// If both n1 and n2 are greater than root, then LCA lies in right
if (node.data < n1 && node.data < n2)
return lca(node.right, n1, n2);
return node;
}
/* Driver program to test lca() */
public static void main(String args[])
{
// Let us construct the BST shown in the above figure
BinaryTree tree = new BinaryTree();
tree.root = new Node(20);
tree.root.left = new Node(8);
tree.root.right = new Node(22);
tree.root.left.left = new Node(4);
tree.root.left.right = new Node(12);
tree.root.left.right.left = new Node(10);
tree.root.left.right.right = new Node(14);
int n1 = 10, n2 = 14;
Node t = tree.lca(tree.root, n1, n2);
System.out.println("LCA of " + n1 + " and " + n2 + " is " +
t.data);
n1 = 14;
n2 = 8;
t = tree.lca(tree.root, n1, n2);
System.out.println("LCA of " + n1 + " and " + n2 + " is " +
t.data);
n1 = 10;
n2 = 22;
t = tree.lca(tree.root, n1, n2);
System.out.println("LCA of " + n1 + " and " + n2 + " is " +
t.data);
}
}
Output:
LCA of 10 and 14 is 12
LCA of 14 and 8 is 8
LCA of 10 and 22 is 20
Time complexity of above solution is O(h) where h is height of tree. Also, the above
solution requires O(h) extra space in function call stack for recursive function calls.
We can avoid extra space using iterative solution.
This approach is wrong as this will return true for below binary tree (and below
tree is not a BST because 4 is in left subtree of 3)
METHOD 2 (Correct but not efficient)
For each node, check if max value in left subtree is smaller than the node and min
value in right subtree greater than the node.
/* Returns true if a binary tree is a binary search tree */
int isBST(struct node* node)
{
if (node == NULL)
return(true);
/* false if the max of the left is > than us */
if (node->left!=NULL && maxValue(node->left) > node->data)
return(false);
/* false if the min of the right is <= than us */
if (node->right!=NULL && minValue(node->right) < node->data)
return(false);
/* false if, recursively, the left or right is not a BST */
if (!isBST(node->left) || !isBST(node->right))
return(false);
/* passing all that, it's a BST */
return(true);
}
It is assumed that you have helper functions minValue() and maxValue() that return
the min or max int value from a non-empty tree.
METHOD 3 (Correct and Efficient):
Method 2 above runs slowly since it traverses over some parts of the tree many
times. A better solution looks at each node only once. The trick is to write a utility
helper function isBSTUtil(struct node* node, int min, int max) that traverses down
the tree keeping track of the narrowing min and max allowed values as it goes,
looking at each node only once. The initial values for min and max should be
INT_MIN and INT_MAX — they narrow from there.
Below is the implementation of the above approach:
//Java implementation to check if given Binary tree
//is a BST or not
/* Class containing left and right child of current
node and key value*/
class Node
{
int data;
Node left, right;
public Node(int item)
{
data = item;
left = right = null;
}
}
public class BinaryTree
{
//Root of the Binary Tree
Node root;
/* can give min and max value according to your code or
can write a function to find min and max value of tree. */
/* returns true if given search tree is binary
search tree (efficient version) */
boolean isBST() {
return isBSTUtil(root, Integer.MIN_VALUE,
Integer.MAX_VALUE);
}
/* Returns true if the given tree is a BST and its
values are >= min and <= max. */
boolean isBSTUtil(Node node, int min, int max)
{
/* an empty tree is BST */
if (node == null)
return true;
/* false if this node violates the min/max constraints */
if (node.data < min || node.data > max)
return false;
/* otherwise check the subtrees recursively
tightening the min/max constraints */
// Allow only distinct values
return (isBSTUtil(node.left, min, node.data-1) &&
isBSTUtil(node.right, node.data+1, max));
}
/* Driver program to test above functions */
public static void main(String args[])
{
BinaryTree tree = new BinaryTree();
tree.root = new Node(4);
tree.root.left = new Node(2);
tree.root.right = new Node(5);
tree.root.left.left = new Node(1);
tree.root.left.right = new Node(3);
if (tree.isBST())
System.out.println("IS BST");
else
System.out.println("Not a BST");
}
}
Output:
IS BST
Time Complexity: O(n)
Auxiliary Space : O(1) if Function Call Stack size is not considered, otherwise O(n)
Simplified Method 3
We can simplify method 2 using NULL pointers instead of INT_MIN and INT_MAX
values.
// Java program to check if a given tree is BST.
class Sol
{
// A binary tree node has data, pointer to
//left child && a pointer to right child /
static class Node
{
int data;
Node left, right;
};
// Returns true if given tree is BST.
static boolean isBST(Node root, Node l, Node r)
{
// Base condition
if (root == null)
return true;
// if left node exist then check it has
// correct data or not i.e. left node's data
// should be less than root's data
if (l != null && root.data <= l.data)
return false;
// if right node exist then check it has
// correct data or not i.e. right node's data
// should be greater than root's data
if (r != null && root.data >= r.data)
return false;
// check recursively for every node.
return isBST(root.left, l, root) &&
isBST(root.right, root, r);
}
// Helper function that allocates a new node with the
//given data && null left && right pointers. /
static Node newNode(int data)
{
Node node = new Node();
node.data = data;
node.left = node.right = null;
return (node);
}
// Driver code
public static void main(String args[])
{
Node root = newNode(3);
root.left = newNode(2);
root.right = newNode(5);
root.left.left = newNode(1);
root.left.right = newNode(4);
if (isBST(root,null,null))
System.out.print("Is BST");
else
System.out.print("Not a BST");
}
}
Output :
Not a BST
Output: 5
Output: 20
The idea is similar to below post.
K’th Largest Element in BST when modification to BST is not allowed
The second largest element is second last element in inorder traversal and second
element in reverse inorder traversal. We traverse given Binary Search Tree in reverse
inorder and keep track of counts of nodes visited. Once the count becomes 2, we
print the node.
Below is the implementation of above idea.
// Java code to find second largest element in BST
// A binary tree node
class Node {
int data;
Node left, right;
Node(int d)
{
data = d;
left = right = null;
}
}
class BinarySearchTree {
// Root of BST
Node root;
// Constructor
BinarySearchTree()
{
root = null;
}
// function to insert new nodes
public void insert(int data)
{
this.root = this.insertRec(this.root, data);
}
/* A utility function to insert a new node with given
key in BST */
Node insertRec(Node node, int data)
{
/* If the tree is empty, return a new node */
if (node == null) {
this.root = new Node(data);
return this.root;
}
/* Otherwise, recur down the tree */
if (data < node.data) {
node.left = this.insertRec(node.left, data);
} else {
node.right = this.insertRec(node.right, data);
}
return node;
}
// class that stores the value of count
public class count {
int c = 0;
}
// Function to find 2nd largest element
void secondLargestUtil(Node node, count C)
{
// Base cases, the second condition is important to
// avoid unnecessary recursive calls
if (node == null || C.c >= 2)
return;
// Follow reverse inorder traversal so that the
// largest element is visited first
this.secondLargestUtil(node.right, C);
// Increment count of visited nodes
C.c++;
// If c becomes k now, then this is the 2nd largest
if (C.c == 2) {
System.out.print("2nd largest element is "+
node.data);
return;
}
// Recur for left subtree
this.secondLargestUtil(node.left, C);
}
// Function to find 2nd largest element
void secondLargest(Node node)
{
// object of class count
count C = new count();
this.secondLargestUtil(this.root, C);
}
// Driver function
public static void main(String[] args)
{
BinarySearchTree tree = new BinarySearchTree();
/* Let us create following BST
50
/ \
30 70
/ \ / \
20 40 60 80 */
tree.insert(50);
tree.insert(30);
tree.insert(20);
tree.insert(40);
tree.insert(70);
tree.insert(60);
tree.insert(80);
tree.secondLargest(tree.root);
}
}
Output:
2nd largest element is 70
Time complexity of the above solution is O(h) where h is height of BST.
Adjacency List:
An array of lists is used. Size of the array is equal to the number of vertices. Let the
array be array[]. An entry array[i] represents the list of vertices adjacent to the ith
vertex. This representation can also be used to represent a weighted graph. The
weights of edges can be represented as lists of pairs. Following is adjacency list
representation of the above graph.
Note that in below implementation, we use dynamic arrays (vector in C++/ArrayList
in Java) to represent adjacency lists instead of linked list. The vector implementation
has advantages of cache friendliness.
// Java Program to demonstrate adjacency list
// representation of graphs
import java.util.LinkedList;
public class GFG
{
// A user define class to represent a graph.
// A graph is an array of adjacency lists.
// Size of array will be V (number of vertices
// in graph)
static class Graph
{
int V;
LinkedList<Integer> adjListArray[];
// constructor
Graph(int V)
{
this.V = V;
// define the size of array as
// number of vertices
adjListArray = new LinkedList[V];
// Create a new list for each vertex
// such that adjacent nodes can be stored
for(int i = 0; i < V ; i++){
adjListArray[i] = new LinkedList<>();
}
}
}
// Adds an edge to an undirected graph
static void addEdge(Graph graph, int src, int dest)
{
// Add an edge from src to dest.
graph.adjListArray[src].add(dest);
// Since graph is undirected, add an edge from dest
// to src also
graph.adjListArray[dest].add(src);
}
// A utility function to print the adjacency list
// representation of graph
static void printGraph(Graph graph)
{
for(int v = 0; v < graph.V; v++)
{
System.out.println("Adjacency list of vertex "+ v);
System.out.print("head");
for(Integer pCrawl: graph.adjListArray[v]){
System.out.print(" -> "+pCrawl);
}
System.out.println("\n");
}
}
// Driver program to test above functions
public static void main(String args[])
{
// create the graph given in above figure
int V = 5;
Graph graph = new Graph(V);
addEdge(graph, 0, 1);
addEdge(graph, 0, 4);
addEdge(graph, 1, 2);
addEdge(graph, 1, 3);
addEdge(graph, 1, 4);
addEdge(graph, 2, 3);
addEdge(graph, 3, 4);
// print the adjacency list representation of
// the above graph
printGraph(graph);
}
}
Output:
Cons: Queries like whether there is an edge from vertex u to vertex v are not
efficient and can be done O(V).
Following are the implementations of simple Breadth First Traversal from a given
source.
The implementation uses adjacency list representation of graphs. STL‘s list
container is used to store lists of adjacent nodes and queue of nodes needed for BFS
traversal.
// Java program to print BFS traversal from a given source vertex.
// BFS(int s) traverses vertices reachable from s.
import java.io.*;
import java.util.*;
// This class represents a directed graph using adjacency list
// representation
class Graph
{
private int V; // No. of vertices
private LinkedList<Integer> adj[]; //Adjacency Lists
// Constructor
Graph(int v)
{
V = v;
adj = new LinkedList[v];
for (int i=0; i<v; ++i)
adj[i] = new LinkedList();
}
// Function to add an edge into the graph
void addEdge(int v,int w)
{
adj[v].add(w);
}
// prints BFS traversal from a given source s
void BFS(int s)
{
// Mark all the vertices as not visited(By default
// set as false)
boolean visited[] = new boolean[V];
// Create a queue for BFS
LinkedList<Integer> queue = new LinkedList<Integer>();
// Mark the current node as visited and enqueue it
visited[s]=true;
queue.add(s);
while (queue.size() != 0)
{
// Dequeue a vertex from queue and print it
s = queue.poll();
System.out.print(s+" ");
// Get all adjacent vertices of the dequeued vertex s
// If a adjacent has not been visited, then mark it
// visited and enqueue it
Iterator<Integer> i = adj[s].listIterator();
while (i.hasNext())
{
int n = i.next();
if (!visited[n])
{
visited[n] = true;
queue.add(n);
}
}
}
}
// Driver method to
public static void main(String args[])
{
Graph g = new Graph(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
System.out.println("Following is Breadth First Traversal "+
"(starting from vertex 2)");
g.BFS(2);
}
}
Output:
Following is Breadth First Traversal (starting from vertex 2)
2031
The above code traverses only the vertices reachable from a given source vertex. All
the vertices may not be reachable from a given vertex (example Disconnected
graph). To do complete DFS traversal of such graphs, we must call DFSUtil() for every
vertex. Also, before calling DFSUtil(), we should check if it is already printed by some
other call of DFSUtil(). Following implementation does the complete graph traversal
even if the nodes are unreachable. The differences from the above code are
highlighted in the below code.
// Java program to print DFS traversal from a given given graph
import java.io.*;
import java.util.*;
// This class represents a directed graph using adjacency list
// representation
class Graph
{
private int V; // No. of vertices
// Array of lists for Adjacency List Representation
private LinkedList<Integer> adj[];
// Constructor
Graph(int v)
{
V = v;
adj = new LinkedList[v];
for (int i=0; i<v; ++i)
adj[i] = new LinkedList();
}
//Function to add an edge into the graph
void addEdge(int v, int w)
{
adj[v].add(w); // Add w to v's list.
}
// A function used by DFS
void DFSUtil(int v,boolean visited[])
{
// Mark the current node as visited and print it
visited[v] = true;
System.out.print(v+" ");
// Recur for all the vertices adjacent to this vertex
Iterator<Integer> i = adj[v].listIterator();
while (i.hasNext())
{
int n = i.next();
if (!visited[n])
DFSUtil(n,visited);
}
}
// The function to do DFS traversal. It uses recursive DFSUtil()
void DFS()
{
// Mark all the vertices as not visited(set as
// false by default in java)
boolean visited[] = new boolean[V];
// Call the recursive helper function to print DFS traversal
// starting from all vertices one by one
for (int i=0; i<V; ++i)
if (visited[i] == false)
DFSUtil(i, visited);
}
public static void main(String args[])
{
Graph g = new Graph(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
System.out.println("Following is Depth First Traversal");
g.DFS();
}
}
Output:
Following is Depth First Traversal
0123
Time Complexity: O(V+E) where V is number of vertices in the graph and E is number
of edges in the graph.
7) Solving puzzles with only one solution, such as mazes. (DFS can be adapted to
find all solutions to a maze by only including nodes on the current path in the visited
set.)
3) Crawlers in Search Engines: Crawlers build index using Breadth First. The idea is to
start from source page and follow all links from source and keep doing same. Depth
First Traversal can also be used for crawlers, but the advantage with Breadth First
Traversal is, depth or levels of the built tree can be limited.
4) Social Networking Websites: In social networks, we can find people within a given
distance ‘k’ from a person using Breadth First Search till ‘k’ levels.
5) GPS Navigation systems: Breadth First Search is used to find all neighboring
locations.
6) Broadcasting in Network: In networks, a broadcasted packet follows Breadth First
Search to reach all nodes.
7) In Garbage Collection: Breadth First Search is used in copying garbage collection
using Cheney’s algorithm. Refer this and for details. Breadth First Search is
preferred over Depth First Search because of better locality of reference:
8) Cycle detection in undirected graph: In undirected graphs, either Breadth First
Search or Depth First Search can be used to detect cycle. In directed graph, only
depth first search can be used.
9) Ford–Fulkerson algorithm In Ford-Fulkerson algorithm, we can either use Breadth
First or Depth First Traversal to find the maximum flow. Breadth First Traversal is
preferred as it reduces worst case time complexity to O(VE2).
10) To test if a graph is Bipartite We can either use Breadth First or Depth First
Traversal.
11) Path Finding We can either use Breadth First or Depth First Traversal to find if
there is a path between two vertices.
12) Finding all nodes within one connected component: We can either use Breadth
First or Depth First Traversal to find all nodes reachable from a given node.
Many algorithms like Prim’s Minimum Spanning Tree and Dijkstra’s Single Source
Shortest Path use structure similar to Breadth First Search.
There can be many more applications as Breadth First Search is one of the core
algorithms for Graphs.
Graph Cycle :
For a disconnected graph, we get the DFS forest as output. To detect cycle, we can
check for a cycle in individual trees by checking back edges.
To detect a back edge, we can keep track of vertices currently in recursion stack of
function for DFS traversal. If we reach a vertex that is already in the recursion stack,
then there is a cycle in the tree. The edge that connects current vertex to the vertex
in the recursion stack is a back edge. We have used recStack[] array to keep track of
vertices in the recursion stack.
Below image is a dry run of the above approach:
Below is the implementation of the above approach:
// A Java Program to detect cycle in a graph
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
class Graph {
private final int V;
private final List<List<Integer>> adj;
public Graph(int V)
{
this.V = V;
adj = new ArrayList<>(V);
for (int i = 0; i < V; i++)
adj.add(new LinkedList<>());
}
// This function is a variation of DFSUytil() in
// https://www.geeksforgeeks.org/archives/18212
private boolean isCyclicUtil(int i, boolean[] visited,
boolean[] recStack)
{
// Mark the current node as visited and
// part of recursion stack
if (recStack[i])
return true;
if (visited[i])
return false;
visited[i] = true;
recStack[i] = true;
List<Integer> children = adj.get(i);
for (Integer c: children)
if (isCyclicUtil(c, visited, recStack))
return true;
recStack[i] = false;
return false;
}
private void addEdge(int source, int dest) {
adj.get(source).add(dest);
}
// Returns true if the graph contains a
// cycle, else false.
// This function is a variation of DFS() in
// https://www.geeksforgeeks.org/archives/18212
private boolean isCyclic()
{
// Mark all the vertices as not visited and
// not part of recursion stack
boolean[] visited = new boolean[V];
boolean[] recStack = new boolean[V];
// Call the recursive helper function to
// detect cycle in different DFS trees
for (int i = 0; i < V; i++)
if (isCyclicUtil(i, visited, recStack))
return true;
return false;
}
// Driver code
public static void main(String[] args)
{
Graph graph = new Graph(4);
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(1, 2);
graph.addEdge(2, 0);
graph.addEdge(2, 3);
graph.addEdge(3, 3);
if(graph.isCyclic())
System.out.println("Graph contains cycle");
else
System.out.println("Graph doesn't "
+ "contain cycle");
}
}
Output:
Graph contains cycle
Time Complexity of this method is same as time complexity of DFS traversal which is
O(V+E).
Output:
Graph contains cycle
Graph doesn't contain cycle
Time Complexity: The program does a simple DFS Traversal of graph and graph is
represented using adjacency list. So the time complexity is O(V+E)