0% found this document useful (0 votes)
201 views

Binary Search Tree

A binary search tree (BST) is a binary tree data structure that has the following properties: 1) The left subtree of a node contains only nodes with keys less than the node's key. 2) The right subtree of a node contains only nodes with keys greater than the node's key. 3) The left and right subtrees must also be binary search trees.

Uploaded by

priyanjay
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
201 views

Binary Search Tree

A binary search tree (BST) is a binary tree data structure that has the following properties: 1) The left subtree of a node contains only nodes with keys less than the node's key. 2) The right subtree of a node contains only nodes with keys greater than the node's key. 3) The left and right subtrees must also be binary search trees.

Uploaded by

priyanjay
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 56

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 :

Binary Search Tree | Set 1 (Search and


Insertion)
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.
There must be no duplicate nodes.
The above properties of Binary Search Tree provide an ordering among keys so that
the operations like search, minimum and maximum can be done fast. If there is no
ordering, then we may have to compare every key to search a given key.

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

// Java program to demonstrate insert 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 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.println(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);
  
        // print inorder traversal of the BST
        tree.inorder();
    }
}

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)

Advantages of BST over Hash Table


Hash Table supports following operations in Θ(1) time.
1) Search
2) Insert
3) Delete
The time complexity of above operations in a self-balancing Binary Search Tree
(BST) (like Red-Black Tree, AVL Tree, Splay Tree, etc) is O(Logn).
So Hash Table seems to beating BST in all common operations. When should we
prefer BST over Hash Tables, what are advantages. Following are some important
points in favor of BSTs.

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.

Construct BST from given preorder


traversal | Set 1
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

Method 1 ( O(n^2) time complexity )


The first element of preorder traversal is always root. We first construct the root.
Then we find the index of first element which is greater than root. Let the index be
‘i’. The values between root and ‘i’ will be part of left subtree, and the values
between ‘i+1’ and ‘n-1’ will be part of right subtree. Divide given pre[] at index “i”
and recur for left and right sub-trees.
For example in {10, 5, 1, 7, 40, 50}, 10 is the first element, so we make it root. Now
we look for the first element greater than 10, we find 40. So we know the structure
of BST is as following.
10
/ \
/ \
{5, 1, 7} {40, 50}
We recursively follow above steps for subarrays {5, 1, 7} and {40, 50}, and get the
complete tree.
// Java program to construct BST from given preorder traversal
  
// A binary tree node
class Node {
  
    int data;
    Node left, right;
  
    Node(int d) {
        data = d;
        left = right = null;
    }
}
  
class Index {
  
    int index = 0;
}
  
class BinaryTree {
  
    Index index = new Index();
      
    // A recursive function to construct Full from pre[]. preIndex is used
    // to keep track of index in pre[].
    Node constructTreeUtil(int pre[], Index preIndex,
            int low, int high, int size) {
          
        // Base case
        if (preIndex.index >= size || low > high) {
            return null;
        }
  
        // The first node in preorder traversal is root. So take the node
at
        // preIndex from pre[] and make it root, and increment preIndex
        Node root = new Node(pre[preIndex.index]);
        preIndex.index = preIndex.index + 1;
  
        // If the current subarry has only one element, no need to recur
        if (low == high) {
            return root;
        }
  
        // Search for the first element greater than root
        int i;
        for (i = low; i <= high; ++i) {
            if (pre[i] > root.data) {
                break;
            }
        }
  
        // Use the index of element found in preorder to divide 
        // preorder array in two parts. Left subtree and right subtree
        root.left = constructTreeUtil(pre, preIndex, preIndex.index, 
                                      i - 1, size);
        root.right = constructTreeUtil(pre, preIndex, i, high, size);
  
        return root;
    }
  
    // The main function to construct BST from given preorder traversal.
    // This function mainly uses constructTreeUtil()
    Node constructTree(int pre[], int size) {
        return constructTreeUtil(pre, index, 0, size - 1, size);
    }
  
    // A utility function to print inorder traversal of a Binary Tree
    void printInorder(Node node) {
        if (node == null) {
            return;
        }
        printInorder(node.left);
        System.out.print(node.data + " ");
        printInorder(node.right);
    }
  
    // Driver program to test above functions
    public static void main(String[] args) {
        BinaryTree tree = new BinaryTree();
        int pre[] = new int[]{10, 5, 1, 7, 40, 50};
        int size = pre.length;
        Node root = tree.constructTree(pre, size);
        System.out.println("Inorder traversal of the constructed tree is
");
        tree.printInorder(root);
    }
}
Output:
Inorder traveral of the constructed tree:
1 5 7 10 40 50
Time Complexity: O(n^2)

Method 2 ( O(n) time complexity )


The idea used here is inspired from method 3 of this post. The trick is to set a range
{min .. max} for every node. Initialize the range as {INT_MIN .. INT_MAX}. The first
node will definitely be in range, so create root node. To construct the left subtree,
set the range as {INT_MIN …root->data}. If a values is in the range {INT_MIN .. root-
>data}, the values is part part of left subtree. To construct the right subtree, set the
range as {root->data..max .. INT_MAX}.

// Java program to construct BST from given preorder traversal


  
// A binary tree node
class Node {
  
    int data;
    Node left, right;
  
    Node(int d) {
        data = d;
        left = right = null;
    }
}
  
class Index {
  
    int index = 0;
}
  
class BinaryTree {
  
    Index index = new Index();
  
    // A recursive function to construct BST from pre[]. preIndex is used
    // to keep track of index in pre[].
    Node constructTreeUtil(int pre[], Index preIndex, int key,
            int min, int max, int size) {
  
        // Base case
        if (preIndex.index >= size) {
            return null;
        }
  
        Node root = null;
  
        // If current element of pre[] is in range, then
        // only it is part of current subtree
        if (key > min && key < max) {
  
            // Allocate memory for root of this 
            // subtree and increment *preIndex
            root = new Node(key);
            preIndex.index = preIndex.index + 1;
  
            if (preIndex.index < size) {
  
                // Contruct the subtree under root
                // All nodes which are in range {min .. key} 
                // will go in left subtree, and first such 
                // node will be root of left subtree.
                root.left = constructTreeUtil(pre, preIndex, 
                            pre[preIndex.index], min, key, size);
  
                // All nodes which are in range {key..max} 
                // will go in right subtree, and first such
                // node will be root of right subtree.
                root.right = constructTreeUtil(pre, preIndex, 
                             pre[preIndex.index], key, max, size);
            }
        }
  
        return root;
    }
  
    // The main function to construct BST from given preorder traversal.
    // This function mainly uses constructTreeUtil()
    Node constructTree(int pre[], int size) {
        int preIndex = 0;
        return constructTreeUtil(pre, index, pre[0], Integer.MIN_VALUE,
                Integer.MAX_VALUE, size);
    }
  
    // A utility function to print inorder traversal of a Binary Tree
    void printInorder(Node node) {
        if (node == null) {
            return;
        }
        printInorder(node.left);
        System.out.print(node.data + " ");
        printInorder(node.right);
    }
  
    // Driver program to test above functions
    public static void main(String[] args) {
        BinaryTree tree = new BinaryTree();
        int pre[] = new int[]{10, 5, 1, 7, 40, 50};
        int size = pre.length;
        Node root = tree.constructTree(pre, size);
        System.out.println("Inorder traversal of the constructed tree is
");
        tree.printInorder(root);
    }
}

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.

1. Create an empty stack.


2. Make the first value as root. Push it to the stack.
3. Keep on popping while the stack is not empty and the next value is greater than
stack’s top value. Make this value as the right child of the last popped node. Push the
new node to the stack.
4. If the next value is less than the stack’s top value, make this value as the left child
of the stack’s top node. Push the new node to the stack.
5. Repeat steps 2 and 3 until there are items remaining in pre[].
// Java program to construct BST from given preorder traversal
  
import java.util.*;
  
// A binary tree node
class Node {
  
    int data;
    Node left, right;
  
    Node(int d) {
        data = d;
        left = right = null;
    }
}
  
class BinaryTree {
  
    // The main function that constructs BST from pre[]
    Node constructTree(int pre[], int size) {
  
        // The first element of pre[] is always root
        Node root = new Node(pre[0]);
  
        Stack<Node> s = new Stack<Node>();
  
        // Push root
        s.push(root);
  
        // Iterate through rest of the size-1 items of given preorder array
        for (int i = 1; i < size; ++i) {
            Node temp = null;
  
            /* Keep on popping while the next value is greater than
             stack's top value. */
            while (!s.isEmpty() && pre[i] > s.peek().data) {
                temp = s.pop();
            }
  
            // Make this greater value as the right child
            // and push it to the stack
            if (temp != null) {
                temp.right = new Node(pre[i]);
                s.push(temp.right);
            } 
              
            // If the next value is less than the stack's top
            // value, make this value as the left child of the 
            // stack's top node. Push the new node to stack
            else {
                temp = s.peek();
                temp.left = new Node(pre[i]);
                s.push(temp.left);
            }
        }
  
        return root;
    }
  
    // A utility function to print inorder traversal of a Binary Tree
    void printInorder(Node node) {
        if (node == null) {
            return;
        }
        printInorder(node.left);
        System.out.print(node.data + " ");
        printInorder(node.right);
    }
  
    // Driver program to test above functions
    public static void main(String[] args) {
        BinaryTree tree = new BinaryTree();
        int pre[] = new int[]{10, 5, 1, 7, 40, 50};
        int size = pre.length;
        Node root = tree.constructTree(pre, size);
        System.out.println("Inorder traversal of the constructed tree is
");
        tree.printInorder(root);
    }
}

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).

Sorted Linked List to Balanced BST


Given a Singly Linked List which has data members sorted in ascending order.
Construct a Balanced Binary Search Tree which has same data members as the given
Linked List.

Examples:
Input: Linked List 1->2->3
Output: A Balanced BST
2
/ \
1 3

Input: Linked List 1->2->3->4->5->6->7


Output: A Balanced BST
4
/ \
2 6
/ \ /\
1 3 5 7

Input: Linked List 1->2->3->4


Output: A Balanced BST
3
/ \
2 4
/
1

Input: Linked List 1->2->3->4->5->6


Output: A Balanced BST
4
/ \
2 6
/ \ /
1 3 5
Method 1 (Simple)
Following is a simple algorithm where we first find the middle node of the list and
make it the root of the tree to be constructed.
1) Get the Middle of the linked list and make it root.
2) Recursively do same for the left half and right half.
a) Get the middle of the left half and make it left child of the root
created in step 1.
b) Get the middle of right half and make it the right child
of the
root created in step 1.

Time complexity: O(nLogn) where n is the number of nodes in Linked List.

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)

Sorted Array to Balanced BST


Given a sorted array. Write a function that creates a Balanced Binary Search Tree
using array elements.
Examples:
Input: Array {1, 2, 3}
Output: A Balanced BST
2
/ \
1 3

Input: Array {1, 2, 3, 4}


Output: A Balanced BST
3
/ \
2 4
/
1

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.

1) Get the Middle of the array and make it root.


2) Recursively do same for left half and right half.
a) Get the middle of left half and make it left child of the root
created in step 1.
b) Get the middle of right half and make it right child of the
root created in step 1.
Following is the implementation of the above algorithm. The main code which
creates Balanced BST is highlighted.

// Java program to print BST in given range


  
// A binary tree node
class Node {
      
    int data;
    Node left, right;
      
    Node(int d) {
        data = d;
        left = right = null;
    }
}
  
class BinaryTree {
      
    static Node root;
  
    /* A function that constructs Balanced Binary Search Tree 
     from a sorted array */
    Node sortedArrayToBST(int arr[], int start, int end) {
  
        /* Base Case */
        if (start > end) {
            return null;
        }
  
        /* Get the middle element and make it root */
        int mid = (start + end) / 2;
        Node node = new Node(arr[mid]);
  
        /* Recursively construct the left subtree and make it
         left child of root */
        node.left = sortedArrayToBST(arr, start, mid - 1);
  
        /* Recursively construct the right subtree and make it
         right child of root */
        node.right = sortedArrayToBST(arr, mid + 1, end);
          
        return node;
    }
  
    /* A utility function to print preorder traversal of BST */
    void preOrder(Node node) {
        if (node == null) {
            return;
        }
        System.out.print(node.data + " ");
        preOrder(node.left);
        preOrder(node.right);
    }
      
    public static void main(String[] args) {
        BinaryTree tree = new BinaryTree();
        int arr[] = new int[]{1, 2, 3, 4, 5, 6, 7};
        int n = arr.length;
        root = tree.sortedArrayToBST(arr, 0, n - 1);
        System.out.println("Preorder traversal of constructed BST");
        tree.preOrder(root);
    }
}

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)

Checking and Searching :

Find the node with minimum value in a


Binary Search Tree
This is quite simple. Just traverse the node from root to left recursively until left is
NULL. The node whose left is NULL is the node with minimum value.

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.

// Java program to find minimum value node in Binary Search Tree


  
// A binary tree node
class Node {
  
    int data;
    Node left, right;
  
    Node(int d) {
        data = d;
        left = right = null;
    }
}
  
class BinaryTree {
  
    static Node head;
      
    /* Given a binary search tree and a number, 
     inserts a new node with the given number in 
     the correct place in the tree. Returns the new 
     root pointer which the caller should then use 
     (the standard trick to avoid using reference 
     parameters). */
    Node insert(Node node, int data) {
          
        /* 1. If the tree is empty, return a new,     
         single node */
        if (node == null) {
            return (new Node(data));
        } else {
              
            /* 2. Otherwise, recur down the tree */
            if (data <= node.data) {
                node.left = insert(node.left, data);
            } else {
                node.right = insert(node.right, data);
            }
  
            /* return the (unchanged) node pointer */
            return node;
        }
    }
  
    /* Given a non-empty binary search tree,  
     return the minimum data value found in that 
     tree. Note that the entire tree does not need 
     to be searched. */
    int minvalue(Node node) {
        Node current = node;
  
        /* loop down to find the leftmost leaf */
        while (current.left != null) {
            current = current.left;
        }
        return (current.data);
    }
      
    // Driver program to test above functions
    public static void main(String[] args) {
        BinaryTree tree = new BinaryTree();
        Node root = null;
        root = tree.insert(root, 4);
        tree.insert(root, 2);
        tree.insert(root, 1);
        tree.insert(root, 3);
        tree.insert(root, 6);
        tree.insert(root, 5);
  
        System.out.println("Minimum value of BST is " +
tree.minvalue(root));
    }
}
  
Output:
Minimum value in BST is 1

Time Complexity: O(n) Worst case happens for left skewed trees.

Lowest Common Ancestor in a Binary


Search Tree.
Given values of two values n1 and n2 in a Binary Search Tree, find
the Lowest Common Ancestor (LCA). You may assume that both the values exist in
the tree.

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.

/* Function to find LCA of n1 and n2. 


The function assumes that both 
n1 and n2 are present in BST */
static node lca(node root, int n1, int n2) 

    while (root != null) 
    { 
        // If both n1 and n2 are smaller 
        // than root, then LCA lies in left 
        if (root.data > n1 && 
            root.data > n2) 
        root = root.left; 
  
        // If both n1 and n2 are greater 
        // than root, then LCA lies in right 
        else if (root.data < n1 && 
                 root.data < n2) 
        root = root.right; 
  
        else break; 
    } 
    return root; 

A program to check if a binary tree is
BST or not
A binary search tree (BST) is a node based binary tree data structure which has the
following properties.
• The left subtree of a node contains only nodes with keys less than the node’s key.
• The right subtree of a node contains only nodes with keys greater than the node’s
key.
• Both the left and right subtrees must also be binary search trees.
From the above properties it naturally follows that:
• Each node (item in the tree) has a distinct key.

METHOD 1 (Simple but Wrong)


Following is a simple program. For each node, check if the left node of it is smaller
than the node and right node of it is greater than the node.
int isBST(struct node* node) 

  if (node == NULL) 
    return 1; 
      
  /* false if left is > than node */
  if (node->left != NULL && node->left->data > node->data) 
    return 0; 
      
  /* false if right is < than node */
  if (node->right != NULL && node->right->data < node->data) 
    return 0; 
    
  /* false if, recursively, the left or right is not a BST */
  if (!isBST(node->left) || !isBST(node->right)) 
    return 0; 
      
  /* passing all that, it's a BST */
  return 1; 
}

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

Second largest element in BST


Given a Binary Search Tree(BST), find the second largest element.
Examples:
Input: Root of below BST
10
/
5

Output: 5

Input: Root of below BST


10
/ \
5 20
\
30

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.

Graph Data Structure And Algorithms


A Graph is a non-linear data structure consisting of nodes and edges. The nodes are
sometimes also referred to as vertices and the edges are lines or arcs that connect
any two nodes in the graph. More formally a Graph can be defined as,
A Graph consists of a finite set of vertices(or nodes) and set of Edges
which connect a pair of nodes.
In the above Graph, the set of vertices V = {0,1,2,3,4} and the set of edges E = {01,
12, 23, 34, 04, 14, 13}.
Graphs are used to solve many real-life problems. Graphs are used to represent
networks. The networks may include paths in a city or telephone network or circuit
network. Graphs are also used in social networks like linkedIn, Facebook. For
example, in Facebook, each person is represented with a vertex(or node). Each node
is a structure and contains information like person id, name, gender, locale etc.

Introduction, DFS and BFS :


Graph and its representations
Graph is a data structure that consists of following two components:
1. A finite set of vertices also called as nodes.
2. A finite set of ordered pair of the form (u, v) called as edge. The pair is ordered
because (u, v) is not same as (v, u) in case of a directed graph(di-graph). The pair of
the form (u, v) indicates that there is an edge from vertex u to vertex v. The edges
may contain weight/value/cost.
Graphs are used to represent many real-life applications: Graphs are used to
represent networks. The networks may include paths in a city or telephone network
or circuit network. Graphs are also used in social networks like linkedIn, Facebook.
For example, in Facebook, each person is represented with a vertex(or node). Each
node is a structure and contains information like person id, name, gender and locale.
See this for more applications of graph.
Following is an example of an undirected graph with 5 vertices.

Following two are the most commonly used representations of a graph.


1. Adjacency Matrix
2. Adjacency List
There are other representations also like, Incidence Matrix and Incidence List. The
choice of the graph representation is situation specific. It totally depends on the type
of operations to be performed and ease of use.
Adjacency Matrix:
Adjacency Matrix is a 2D array of size V x V where V is the number of vertices in a
graph. Let the 2D array be adj[][], a slot adj[i][j] = 1 indicates that there is an edge
from vertex i to vertex j. Adjacency matrix for undirected graph is always symmetric.
Adjacency Matrix is also used to represent weighted graphs. If adj[i][j] = w, then
there is an edge from vertex i to vertex j with weight w.
The adjacency matrix for the above example graph is:

Pros: Representation is easier to implement and follow. Removing an edge takes


O(1) time. Queries like whether there is an edge from vertex ‘u’ to vertex ‘v’ are
efficient and can be done O(1).
Cons: Consumes more space O(V^2). Even if the graph is sparse(contains less
number of edges), it consumes the same space. Adding a vertex is O(V^2) time.
Please see this for a sample Python implementation of adjacency matrix.

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:

Adjacency list of vertex 0


head -> 1-> 4

Adjacency list of vertex 1


head -> 0-> 2-> 3-> 4
Adjacency list of vertex 2
head -> 1-> 3

Adjacency list of vertex 3


head -> 1-> 2-> 4

Adjacency list of vertex 4


head -> 0-> 1-> 3
Pros: Saves space O(|V|+|E|) . In the worst case, there can be C(V, 2) number of
edges in a graph thus consuming O(V^2) space. Adding a vertex is easier.

Cons: Queries like whether there is an edge from vertex u to vertex v are not
efficient and can be done O(V).

Breadth First Search or BFS for a Graph


Breadth First Traversal (or Search) for a graph is similar to Breadth First Traversal of a
tree (See method 2 of this post). The only catch here is, unlike trees, graphs may
contain cycles, so we may come to the same node again. To avoid processing a node
more than once, we use a boolean visited array. For simplicity, it is assumed that all
vertices are reachable from the starting vertex.
For example, in the following graph, we start traversal from vertex 2. When we come
to vertex 0, we look for all adjacent vertices of it. 2 is also an adjacent vertex of 0. If
we don’t mark visited vertices, then 2 will be processed again and it will become a
non-terminating process. A Breadth First Traversal of the following graph is 2, 0, 3, 1.

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

Depth First Search or DFS for a Graph


Depth First Traversal (or Search) for a graph is similar to Depth First Traversal of a
tree. The only catch here is, unlike trees, graphs may contain cycles, so we may come
to the same node again. To avoid processing a node more than once, we use a
boolean visited array.
For example, in the following graph, we start traversal from vertex 2. When we come
to vertex 0, we look for all adjacent vertices of it. 2 is also an adjacent vertex of 0. If
we don’t mark visited vertices, then 2 will be processed again and it will become a
non-terminating process. A Depth First Traversal of the following graph is 2, 0, 1, 3.
See this post for all applications of Depth First Traversal.
Following are implementations of simple Depth First Traversal. The C++
implementation uses adjacency list representation of graphs. STL‘s list container is
used to store lists of adjacent nodes.
// 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(int v)
    {
        // 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
        DFSUtil(v, 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 "+
                           "(starting from vertex 2)");
  
        g.DFS(2);
    }
}
Output:
Following is Depth First Traversal (starting from vertex 2)
2013

How to handle disconnected graph?

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.

Applications of Depth First Search


Depth-first search (DFS) is an algorithm (or technique) for traversing a graph.
Following are the problems that use DFS as a building block.
1) For an unweighted graph, DFS traversal of the graph produces the minimum
spanning tree and all pair shortest path tree.
2) Detecting cycle in a graph
A graph has cycle if and only if we see a back edge during DFS. So we can run DFS for
the graph and check for back edges. (See this for details)
3) Path Finding
We can specialize the DFS algorithm to find a path between two given vertices u and
z.
i) Call DFS(G, u) with u as the start vertex.
ii) Use a stack S to keep track of the path between the start vertex and the current
vertex.
iii) As soon as destination vertex z is encountered, return the path as the
contents of the stack
See this for details.
4) Topological Sorting
Topological Sorting is mainly used for scheduling jobs from the given dependencies
among jobs. In computer science, applications of this type arise in instruction
scheduling, ordering of formula cell evaluation when recomputing formula values in
spreadsheets, logic synthesis, determining the order of compilation tasks to perform
in makefiles, data serialization, and resolving symbol dependencies in linkers [2].
5) To test if a graph is bipartite
We can augment either BFS or DFS when we first discover a new vertex, color it
opposited its parents, and for each other edge, check it doesn’t link two vertices of
the same color. The first vertex in any connected component can be red or black!
See this for details.
6) Finding Strongly Connected Components of a graph A directed graph is called
strongly connected if there is a path from each vertex in the graph to every other
vertex. (See this for DFS based algo for finding Strongly Connected Components)

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.)

Applications of Breadth First Traversal


We have earlier discussed Breadth First Traversal Algorithm for Graphs. We have
also discussed Applications of Depth First Traversal. In this article, applications of
Breadth First Search are discussed.
1) Shortest Path and Minimum Spanning Tree for unweighted graph In an
unweighted graph, the shortest path is the path with least number of edges. With
Breadth First, we always reach a vertex from given source using the minimum
number of edges. Also, in case of unweighted graphs, any spanning tree is Minimum
Spanning Tree and we can use either Depth or Breadth first traversal for finding a
spanning tree.
2) Peer to Peer Networks. In Peer to Peer Networks like BitTorrent, Breadth First
Search is used to find all neighbor nodes.

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 :

Detect Cycle in a Directed Graph


Given a directed graph, check whether the graph contains a cycle or not. Your
function should return true if the given graph contains at least one cycle, else return
false. For example, the following graph contains three cycles 0->2->0, 0->1->2->0 and
3->3, so your function must return true.
Depth First Traversal can be used to detect a cycle in a Graph. DFS for a connected
graph produces a tree. There is a cycle in a graph only if there is a back edge present
in the graph. A back edge is an edge that is from a node to itself (self-loop) or one of
its ancestor in the tree produced by DFS. In the following graph, there are 3 back
edges, marked with a cross sign. We can observe that these 3 back edges indicate 3
cycles present in the graph.

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).

Detect cycle in an undirected graph


.
Given an undirected graph, how to check if there is a cycle in the graph? For
example, the following graph has a cycle 1-0-2-1.

We have discussed cycle detection for directed graph. We have also discussed


a union-find algorithm for cycle detection in undirected graphs. The time complexity
of the union-find algorithm is O(ELogV). Like directed graphs, we can use DFS to
detect cycle in an undirected graph in O(V+E) time. We do a DFS traversal of the
given graph. For every visited vertex ‘v’, if there is an adjacent ‘u’ such that u is
already visited and u is not parent of v, then there is a cycle in graph. If we don’t find
such an adjacent for any vertex, we say that there is no cycle. The assumption of this
approach is that there are no parallel edges between any two vertices.
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 an undirected 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
    private LinkedList<Integer> adj[]; // Adjacency List Represntation
  
    // 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);
        adj[w].add(v);
    }
  
    // A recursive function that uses visited[] and parent to detect
    // cycle in subgraph reachable from vertex v.
    Boolean isCyclicUtil(int v, Boolean visited[], int parent)
    {
        // Mark the current node as visited
        visited[v] = true;
        Integer i;
  
        // Recur for all the vertices adjacent to this vertex
        Iterator<Integer> it = adj[v].iterator();
        while (it.hasNext())
        {
            i = it.next();
  
            // If an adjacent is not visited, then recur for that
            // adjacent
            if (!visited[i])
            {
                if (isCyclicUtil(i, visited, v))
                    return true;
            }
  
            // If an adjacent is visited and not parent of current
            // vertex, then there is a cycle.
            else if (i != parent)
                return true;
        }
        return false;
    }
  
    // Returns true if the graph contains a cycle, else false.
    Boolean isCyclic()
    {
        // Mark all the vertices as not visited and not part of
        // recursion stack
        Boolean visited[] = new Boolean[V];
        for (int i = 0; i < V; i++)
            visited[i] = false;
  
        // Call the recursive helper function to detect cycle in
        // different DFS trees
        for (int u = 0; u < V; u++)
            if (!visited[u]) // Don't recur for u if already visited
                if (isCyclicUtil(u, visited, -1))
                    return true;
  
        return false;
    }
  
  
    // Driver method to test above methods
    public static void main(String args[])
    {
        // Create a graph given in the above diagram
        Graph g1 = new Graph(5);
        g1.addEdge(1, 0);
        g1.addEdge(0, 2);
        g1.addEdge(2, 1);
        g1.addEdge(0, 3);
        g1.addEdge(3, 4);
        if (g1.isCyclic())
            System.out.println("Graph contains cycle");
        else
            System.out.println("Graph doesn't contains cycle");
  
        Graph g2 = new Graph(3);
        g2.addEdge(0, 1);
        g2.addEdge(1, 2);
        if (g2.isCyclic())
            System.out.println("Graph contains cycle");
        else
            System.out.println("Graph doesn't contains cycle");
    }
}

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)

You might also like