Introduction to Generic Trees (N-ary Trees)

Generic trees are a collection of nodes where each node is a data structure that consists of records and a list of references to its children(duplicate references are not allowed). Unlike the linked list, each node stores the address of multiple nodes. Every node stores address of its children and the very first node’s address will be stored in a separate pointer called root.

The Generic trees are the N-ary trees which have the following properties: 

            1. Many children at every node.

            2. The number of nodes for each node is not known in advance.

Example: 
 

Generic Tree

To represent the above tree, we have to consider the worst case, that is the node with maximum children (in above example, 6 children) and allocate that many pointers for each node.
The node representation based on this method can be written as:
 

C++




// Node declaration
struct Node{
   int data;
   Node *firstchild;
   Node *secondchild;
   Node *thirdchild;
   Node *fourthchild;
   Node *fifthchild;
   Node *sixthchild;
};

C




//Node declaration
struct Node{
   int data;
   struct Node *firstchild;
   struct Node *secondchild;
   struct Node *thirdchild;
   struct Node *fourthchild;
   struct Node *fifthchild;
   struct Node *sixthchild;
}

Java




// Java code for above approach
public class Node {
    int data;
    Node firstchild;
    Node secondchild;
    Node thirdchild;
    Node fourthchild;
    Node fifthchild;
    Node sixthchild;
}

Python




class Node:
    def __init__(self, data):
        self.data = data
        self.firstchild = None
        self.secondchild = None
        self.thirdchild = None
        self.fourthchild = None
        self.fifthchild = None
        self.sixthchild = None

C#




public class Node
{
    public int Data { get; set; }
    public Node Firstchild { get; set; }
    public Node Secondchild { get; set; }
    public Node Thirdchild { get; set; }
    public Node Fourthchild { get; set; }
    public Node Fifthchild { get; set; }
    public Node Sixthchild { get; set; }
}

Javascript




// Javascript code for above approach
class Node {
    constructor(data) {
        this.data = data;
        this.firstchild = null;
        this.secondchild = null;
        this.thirdchild = null;
        this.fourthchild = null;
        this.fifthchild = null;
        this.sixthchild = null;
    }
}

Disadvantages of the above representation are: 

  1. Memory Wastage – All the pointers are not required in all the cases. Hence, there is lot of memory wastage.
  2. Unknown number of children – The number of children for each node is not known in advance.

Simple Approach: 

For storing the address of children in a node we can use an array or linked list. But we will face some issues with both of them.

  1. In Linked list, we can not randomly access any child’s address. So it will be expensive.
  2. In array, we can randomly access the address of any child, but we can store only fixed number of children’s addresses in it.

Better Approach:

We can use Dynamic Arrays for storing the address of children. We can randomly access any child’s address and the size of the vector is also not fixed.

C++




#include <vector>
  
class Node {
public:
    int data;
    std::vector<Node*> children;
  
    Node(int data)
    {
        this->data = data;
    }
};

C




//Node declaration
struct Node{
    int data;
    vector<Node*> children;
}

Java




import java.util.ArrayList;
  
class Node {
    int data;
    ArrayList<Node> children;
  
    Node(int data)
    {
        this.data = data;
        this.children = new ArrayList<Node>();
    }
}

Python




class Node:
      
    def __init__(self,data):
        self.data=data
        self.children=[]

C#




using System.Collections.Generic;
  
class Node {
    public int data;
    public List<Node> children;
  
    public Node(int data)
    {
        this.data = data;
        this.children = new List<Node>();
    }
}
  
// This code is contributed by adityamaharshi21.

Javascript




class Node {
  constructor(data) {
    this.data = data;
    this.children = [];
  }
}

Efficient Approach:  

First child / Next sibling representation

 In the first child/next sibling representation, the steps taken are: 

At each node-link the children of the same parent(siblings) from left to right.

Since we have a link between children, we do not need extra links from parents to all the children. This representation allows us to traverse all the elements by starting at the first child of the parent.
 

FIRST CHILD/NEXT SIBLING REPRESENTATION

The node declaration for first child / next sibling representation can be written as: 
 

C++




struct Node {
    int data;
    Node *firstChild;
    Node *nextSibling;
};

C




//Node declaration
struct Node{
    int data;
    struct Node *firstChild;
    struct Node *nextSibling;
}

Java




class Node {
    int data;
    Node firstChild;
    Node nextSibling;
}

Python




class Node:
    def __init__(self, data):
        self.data = data
        self.firstChild = None
        self.nextSibling = None
  
        # This code is contributed by aadityamaharshi

Javascript




class Node {
    constructor(data) {
        this.data = data;
        this.firstChild = null;
        this.nextSibling = null;
    }
}

C#




public class Node {
    public int Data
    {
        get;
        set;
    }
    public Node FirstChild
    {
        get;
        set;
    }
    public Node NextSibling
    {
        get;
        set;
    }
}

Advantages: 

Height of generic tree from parent array 
Generic tree – level order traversal



Next
------

Introduction to Binary Tree – Data Structure and Algorithm Tutorials

Binary Tree is a non-linear data structure where each node has at most two children. In this article, we will cover all the basics of Binary Tree, Operations on Binary Tree, its implementation, advantages, disadvantages which will help you solve all the problems based on Binary Tree.
Introduction-to-Binary-Tree

Table of Content

What is Binary Tree?

Binary tree is a tree data structure(non-linear) in which each node can have at most two children which are referred to as the left child and the right child

The topmost node in a binary tree is called the root, and the bottom-most nodes are called leaves. A binary tree can be visualized as a hierarchical structure with the root at the top and the leaves at the bottom.

Representation of Binary Tree

Each node in a Binary Tree has three parts:

Representation-of-Binary-Tree

Below is the representation of a Node of Binary Tree in different languages:

// Use any below method to implement Nodes of tree

// Method 1: Using "struct" to make
// user-define data type
struct node {
    int data;
    struct node* left;
    struct node* right;
};

// Method 2: Using "class" to make
// user-define data type
class Node {
public:
    int data;
    Node* left;
    Node* right;
};
// 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;
    }
}

Types of Binary Tree

Binary Tree can be classified into multiples types based on multiple factors:

Operations On Binary Tree

1. Insertion in Binary Tree

We can insert a node anywhere in a binary tree by inserting the node as the left or right child of any node or by making the node as root of the tree.

Algorithm to insert a node in a Binary Tree:

2. Traversal of Binary Tree

Traversal of Binary Tree involves visiting all the nodes of the binary tree. Tree Traversal algorithms can be classified broadly into two categories:

Depth-First Search (DFS) algorithms:

Breadth-First Search (BFS) algorithms:

3. Deletion in Binary Tree

We can delete any node in the binary tree and rearrange the nodes after deletion to again form a valid binary tree.

Algorithm to delete a node in a Binary Tree:

4. Searching in Binary Tree

We can search for an element in the node by using any of the traversal techniques.

Algorithm to search a node in a Binary Tree:

Auxiliary Operations On Binary Tree

Implementation of Binary Tree

Below is the code for insertion, deletion and traversal of the binary tree:

import java.util.LinkedList;
import java.util.Queue;

// Node class to define the structure of the node
class Node {
    int data;
    Node left, right;
    // Parameterized Constructor
    Node(int val) {
        data = val;
        left = right = null;
    }
}

public class BinaryTree {
    // Function to insert nodes
    public static Node insert(Node root, int data) {
        // If tree is empty, new node becomes the root
        if (root == null) {
            root = new Node(data);
            return root;
        }
        // Queue to traverse the tree and find the position to
        // insert the node
        Queue<Node> q = new LinkedList<>();
        q.offer(root);
        while (!q.isEmpty()) {
            Node temp = q.poll();
            // Insert node as the left child of the parent node
            if (temp.left == null) {
                temp.left = new Node(data);
                break;
            }
            // If the left child is not null push it to the
            // queue
            else
                q.offer(temp.left);
            // Insert node as the right child of parent node
            if (temp.right == null) {
                temp.right = new Node(data);
                break;
            }
            // If the right child is not null push it to the
            // queue
            else
                q.offer(temp.right);
        }
        return root;
    }

    /* function to delete the given deepest node
    (d_node) in binary tree */
    public static void deletDeepest(Node root, Node d_node) {
        Queue<Node> q = new LinkedList<>();
        q.offer(root);
        // Do level order traversal until last node
        Node temp;
        while (!q.isEmpty()) {
            temp = q.poll();
            if (temp == d_node) {
                temp = null;
                d_node = null;
                return;
            }
            if (temp.right != null) {
                if (temp.right == d_node) {
                    temp.right = null;
                    d_node = null;
                    return;
                } else
                    q.offer(temp.right);
            }
            if (temp.left != null) {
                if (temp.left == d_node) {
                    temp.left = null;
                    d_node = null;
                    return;
                } else
                    q.offer(temp.left);
            }
        }
    }

    /* function to delete element in binary tree */
    public static Node deletion(Node root, int key) {
        if (root == null)
            return null;
        if (root.left == null && root.right == null) {
            if (root.data == key)
                return null;
            else
                return root;
        }
        Queue<Node> q = new LinkedList<>();
        q.offer(root);
        Node temp = new Node(0);
        Node key_node = null;
        // Do level order traversal to find deepest
        // node(temp) and node to be deleted (key_node)
        while (!q.isEmpty()) {
            temp = q.poll();
            if (temp.data == key)
                key_node = temp;
            if (temp.left != null)
                q.offer(temp.left);
            if (temp.right != null)
                q.offer(temp.right);
        }
        if (key_node != null) {
            int x = temp.data;
            key_node.data = x;
            deletDeepest(root, temp);
        }
        return root;
    }

    // Inorder tree traversal (Left - Root - Right)
    public static void inorderTraversal(Node root) {
        if (root == null)
            return;
        inorderTraversal(root.left);
        System.out.print(root.data + " ");
        inorderTraversal(root.right);
    }

    // Preorder tree traversal (Root - Left - Right)
    public static void preorderTraversal(Node root) {
        if (root == null)
            return;
        System.out.print(root.data + " ");
        preorderTraversal(root.left);
        preorderTraversal(root.right);
    }

    // Postorder tree traversal (Left - Right - Root)
    public static void postorderTraversal(Node root) {
        if (root == null)
            return;
        postorderTraversal(root.left);
        postorderTraversal(root.right);
        System.out.print(root.data + " ");
    }

    // Function for Level order tree traversal
    public static void levelorderTraversal(Node root) {
        if (root == null)
            return;

        // Queue for level order traversal
        Queue<Node> q = new LinkedList<>();
        q.offer(root);
        while (!q.isEmpty()) {
            Node temp = q.poll();
            System.out.print(temp.data + " ");
            // Push left child in the queue
            if (temp.left != null)
                q.offer(temp.left);
            // Push right child in the queue
            if (temp.right != null)
                q.offer(temp.right);
        }
    }

    /* Driver function to check the above algorithm. */
    public static void main(String[] args) {
        Node root = null;
        // Insertion of nodes
        root = insert(root, 10);
        root = insert(root, 20);
        root = insert(root, 30);
        root = insert(root, 40);

        System.out.print("Preorder traversal: ");
        preorderTraversal(root);

        System.out.print("\nInorder traversal: ");
        inorderTraversal(root);

        System.out.print("\nPostorder traversal: ");
        postorderTraversal(root);

        System.out.print("\nLevel order traversal: ");
        levelorderTraversal(root);

        // Delete the node with data = 20
        root = deletion(root, 20);

        System.out.print("\nInorder traversal after deletion: ");
        inorderTraversal(root);
    }
}
#include <bits/stdc++.h>
using namespace std;

// Node class to define the structure of the node
class Node {
public:
    int data;
    Node *left, *right;
    // Parameterized Constructor
    Node(int val)
    {
        data = val;
        left = right = NULL;
    }
};

// Function to insert nodes
Node* insert(Node* root, int data)
{
    // If tree is empty, new node becomes the root
    if (root == NULL) {
        root = new Node(data);
        return root;
    }
    // queue to traverse the tree and find the position to
    // insert the node
    queue<Node*> q;
    q.push(root);
    while (!q.empty()) {
        Node* temp = q.front();
        q.pop();
        // Insert node as the left child of the parent node
        if (temp->left == NULL) {
            temp->left = new Node(data);
            break;
        }
        // If the left child is not null push it to the
        // queue
        else
            q.push(temp->left);
        // Insert node as the right child of parent node
        if (temp->right == NULL) {
            temp->right = new Node(data);
            break;
        }
        // If the right child is not null push it to the
        // queue
        else
            q.push(temp->right);
    }
    return root;
}

/* function to delete the given deepest node
(d_node) in binary tree */
void deletDeepest(Node* root, Node* d_node)
{
    queue<Node*> q;
    q.push(root);
    // Do level order traversal until last node
    Node* temp;
    while (!q.empty()) {
        temp = q.front();
        q.pop();
        if (temp == d_node) {
            temp = NULL;
            delete (d_node);
            return;
        }
        if (temp->right) {
            if (temp->right == d_node) {
                temp->right = NULL;
                delete (d_node);
                return;
            }
            else
                q.push(temp->right);
        }
        if (temp->left) {
            if (temp->left == d_node) {
                temp->left = NULL;
                delete (d_node);
                return;
            }
            else
                q.push(temp->left);
        }
    }
}

/* function to delete element in binary tree */
Node* deletion(Node* root, int key)
{
    if (!root)
        return NULL;
    if (root->left == NULL && root->right == NULL) {
        if (root->data == key)
            return NULL;
        else
            return root;
    }
    queue<Node*> q;
    q.push(root);
    Node* temp;
    Node* key_node = NULL;
    // Do level order traversal to find deepest
    // node(temp) and node to be deleted (key_node)
    while (!q.empty()) {
        temp = q.front();
        q.pop();
        if (temp->data == key)
            key_node = temp;
        if (temp->left)
            q.push(temp->left);
        if (temp->right)
            q.push(temp->right);
    }
    if (key_node != NULL) {
        int x = temp->data;
        key_node->data = x;
        deletDeepest(root, temp);
    }
    return root;
}

// Inorder tree traversal (Left - Root - Right)
void inorderTraversal(Node* root)
{
    if (!root)
        return;
    inorderTraversal(root->left);
    cout << root->data << " ";
    inorderTraversal(root->right);
}

// Preorder tree traversal (Root - Left - Right)
void preorderTraversal(Node* root)
{
    if (!root)
        return;
    cout << root->data << " ";
    preorderTraversal(root->left);
    preorderTraversal(root->right);
}

// Postorder tree traversal (Left - Right - Root)
void postorderTraversal(Node* root)
{
    if (root == NULL)
        return;
    postorderTraversal(root->left);
    postorderTraversal(root->right);
    cout << root->data << " ";
}

// Function for Level order tree traversal
void levelorderTraversal(Node* root)
{
    if (root == NULL)
        return;

    // Queue for level order traversal
    queue<Node*> q;
    q.push(root);
    while (!q.empty()) {
        Node* temp = q.front();
        q.pop();
        cout << temp->data << " ";
        // Push left child in the queue
        if (temp->left)
            q.push(temp->left);
        // Push right child in the queue
        if (temp->right)
            q.push(temp->right);
    }
}

/* Driver function to check the above algorithm. */
int main()
{
    Node* root = NULL;
    // Insertion of nodes
    root = insert(root, 10);
    root = insert(root, 20);
    root = insert(root, 30);
    root = insert(root, 40);

    cout << "Preorder traversal: ";
    preorderTraversal(root);

    cout << "\nInorder traversal: ";
    inorderTraversal(root);

    cout << "\nPostorder traversal: ";
    postorderTraversal(root);

    cout << "\nLevel order traversal: ";
    levelorderTraversal(root);

    // Delete the node with data = 20
    root = deletion(root, 20);

    cout << "\nInorder traversal after deletion: ";
    inorderTraversal(root);
}

Output
Preorder traversal: 10 20 40 30 
Inorder traversal: 40 20 10 30 
Postorder traversal: 40 20 30 10 
Level order traversal: 10 20 30 40 
Inorder traversal after deletion: 40 10 30 

Complexity Analysis of Binary Tree Operations

Operations Time Complexity

Space Complexity

Insertion O(N)

O(N)

Preorder TraversalO(N)

O(N)

Inorder Traversal

O(N)

O(N)

Postorder TraversalO(N)

O(N)

Level Order TraversalO(N)

O(N)

Deletion

O(N)

O(N)

Searching

O(N)

O(N)

We can use Morris Traversal to traverse all the nodes of the binary tree in O(1) time.

Advantages of Binary Tree

Disadvantages of Binary Tree

Applications of Binary Tree

Frequently Asked Questions on Binary Tree

1. What is a binary tree?

A binary tree is a non-linear data structure consisting of nodes, where each node has at most two children (left child and the right child).

2. What are the types of binary trees?

Binary trees can be classified into various types, including full binary trees, complete binary trees, perfect binary trees, balanced binary trees (such as AVL trees and Red-Black trees), and degenerate (or pathological) binary trees.

3. What is the height of a binary tree?

The height of a binary tree is the length of the longest path from the root node to a leaf node. It represents the number of edges in the longest path from the root node to a leaf node.

4. What is the depth of a node in a binary tree?

The depth of a node in a binary tree is the length of the path from the root node to that particular node. The depth of the root node is 0.

5. How do you perform tree traversal in a binary tree?

Tree traversal in a binary tree can be done in different ways: In-order traversal, Pre-order traversal, Post-order traversal, and Level-order traversal (also known as breadth-first traversal).

6. What is an Inorder traversal in Binary Tree?

In Inorder traversal, nodes are recursively visited in this order: left child, root, right child. This traversal results in nodes being visited in non-decreasing order in a binary search tree.

7. What is a Preorder traversal in Binary Tree?

In Preorder traversal, nodes are recursively visited in this order: root, left child, right child. This traversal results in root node being the first node to be visited.

8. What is a Postorder traversal in Binary Tree?

In Postorder traversal, nodes are recursively visited in this order: left child, right child and root. This traversal results in root node being the last node to be visited.

9. What is the difference between a Binary Tree and a Binary Search Tree?

A binary tree is a hierarchical data structure where each node has at most two children, whereas a binary search tree is a type of binary tree in which the left child of a node contains values less than the node’s value, and the right child contains values greater than the node’s value.

10. What is a balanced binary tree?

A balanced binary tree is a binary tree in which the height of the left and right subtrees of every node differ by at most one. Balanced trees help maintain efficient operations such as searching, insertion, and deletion with time complexities close to O(log n).

Conclusion:

Tree is a hierarchical data structure. Main uses of trees include maintaining hierarchical data, providing moderate access and insert/delete operations. Binary trees are special cases of tree where every node has at most two children.

Related Articles:




Previous
Next
------

Complete Binary Tree

We know a tree is a non-linear data structure. It has no limitation on the number of children. A binary tree has a limitation as any node of the tree has at most two children: a left and a right child.

What is a Complete Binary Tree?

A complete binary tree is a special type of binary tree where all the levels of the tree are filled completely except the lowest level nodes which are filled from as left as possible.

Complete Binary Tree

Some terminology of Complete Binary Tree:

Properties of Complete Binary Tree:

Perfect Binary Tree vs Complete Binary Tree:

A binary tree of height ‘h’ having the maximum number of nodes is a perfect binary tree. 
For a given height h, the maximum number of nodes is 2h+1-1.

A complete binary tree of height h is a perfect binary tree up to height h-1, and in the last level element are stored in left to right order.

Example 1:

A Binary Tree

The height of the given binary tree is 2 and the maximum number of nodes in that tree is n= 2h+1-1 =  22+1-1 =  23-1 = 7.
Hence we can conclude it is a perfect binary tree.
Now for a complete binary tree, It is full up to height h-1 i.e.; 1, and the last level elements are stored in left to right order. Hence it is a complete Binary tree also. Here is the representation of elements when stored in an array

Element stored in an array level by level

In the array, all the elements are stored continuously.

Example 2:

A binary tree

Height of the given binary tree is 2 and the maximum number of nodes that should be there are 2h+1 – 1 = 22+1 – 1 = 23 – 1 = 7
But the number of nodes in the tree is 6. Hence it is not a perfect binary tree.
Now for a complete binary tree, It is full up to height h-1 i.e.; 1, and the last level element are stored in left to right order. Hence this is a complete binary tree. Store the element in an array and it will be like;

Element stored in an array level by level

Example 3:

A binary tree

The height of the binary tree is 2 and the maximum number of nodes that can be there is 7, but there are only 5 nodes hence it is not a perfect binary tree.
In case of a complete binary tree, we see that in the last level elements are not filled from left to right order. So it is not a complete binary tree.

Element stored in an array level by level

The elements in the array are not continuous.

Full Binary Tree vs Complete Binary tree:

For a full binary tree, every node has either 2 children or 0 children.

Example 1:

A binary tree

In the given binary tree there is no node having degree 1, either 2 or 0 children for every node, hence it is a full binary tree.

For a complete binary tree, elements are stored in level by level and not from the leftmost side in the last level. Hence this is not a complete binary tree. The array representation is:

Element stored in an array level by level

Example 2:

A binary Tree

In the given binary tree there is no node having degree 1. Every node has a degree of either 2 or 0. Hence it is a full binary tree.

For a complete binary tree, elements are stored in a level by level manner and filled from the leftmost side of the last level. Hence this a complete binary tree. Below is the array representation of the tree:

Element stored in an array level by level

Example 3:

A binary tree

In the given binary tree node B has degree 1 which violates the property of full binary tree hence it is not a full Binary tree

For a complete binary tree, elements are stored in level by level manner and filled from the leftmost side of the last level. Hence this is a complete binary tree. Array representation of the binary tree is:

Element stored in an array level by level

Example 4:
 

a binary tree

In the given binary tree node C has degree 1 which violates the property of a full binary tree hence it is not a full Binary tree

For a complete binary tree, elements are stored in level by level manner and filled from the leftmost side of the last level. Here node E violates the condition. Hence this is not a complete binary tree

Creation of Complete Binary Tree:

We know a complete binary tree is a tree in which except for the last level (say l)all the other level has (2l) nodes and the nodes are lined up from left to right side.
It can be represented using an array. If the parent is it index i so the left child is at 2i+1 and the right child is at 2i+2.

Complete binary tree and its array representation

Algorithm:

For the creation of a Complete Binary Tree, we require a queue data structure to keep track of the inserted nodes.

Step 1: Initialize the root with a new node when the tree is empty.

Step 2: If the tree is not empty then get the front element 

Step 3: If the node has both the children then pop it from the queue.

Step 4: Enqueue the new data.

Illustration:

Consider the below array:

1. The 1st element will the root (value at index = 0)

A is taken as root

2. The next element (at index = 1) will be left and third element (index = 2) will be right child of root

B as left child and D as right child

3. fourth (index = 3) and fifth element (index = 4) will be the left and right child of B node

E and F are left and right child of B

4. Next element (index = 5) will be left child of the node D

G is made left child of D node

This is how complete binary tree is created.

Implementation: For the implementation of building a Complete Binary Tree from level order traversal is given in this post.

Application of the Complete binary tree:

Check if a given binary tree is complete or not: Follow this post to check if the given binary tree is complete or not.



Previous
Next
------

Perfect Binary Tree

What is a Perfect Binary Tree?

A perfect binary tree is a special type of binary tree in which all the leaf nodes are at the same depth, and all non-leaf nodes have two children. In simple terms, this means that all leaf nodes are at the maximum depth of the tree, and the tree is completely filled with no gaps.

The maximum number of nodes in a perfect binary tree is given by the formula 2^(d+1) – 1, where d is the depth of the tree. This means that a perfect binary tree with a depth of n has 2^n leaf nodes and a total of 2^(n+1) – 1 nodes.

Perfect binary trees have a number of useful properties that make them useful in various applications. For example, they are often used in the implementation of heap data structures, as well as in the construction of threaded binary trees. They are also used in the implementation of algorithms such as heapsort and merge sort.

In other words, it can be said that each level of the tree is completely filled by the nodes.

Examples of Perfect Binary Tree: 

Example of a Perfect Binary Tree

Example of a Perfect Binary Tree

A tree with only the root node is also a perfect binary tree.     

Example-2

The following tree is not a perfect binary tree because the last level of the tree is not completely filled.

Not a Perfect Binary Tree

Not a Perfect Binary Tree

Properties of a Perfect Binary Tree:

Check whether a tree is a Perfect Binary Tree or not:

For more information about this refer to the article article: Check whether a given binary tree is perfect or not

Summary:


Previous
Next
------

Balanced Binary Tree

A binary tree is balanced if the height of the tree is O(Log n) where n is the number of nodes. For Example, the AVL tree maintains O(Log n) height by making sure that the difference between the heights of the left and right subtrees is at most 1. Red-Black trees maintain O(Log n) height by making sure that the number of Black nodes on every root-to-leaf path is the same and that there are no adjacent red nodes. Balanced Binary Search trees are performance-wise good as they provide O(log n) time for search, insert and delete. 

A balanced binary tree is a binary tree that follows the 3 conditions:

A single node is always balanced. It is also referred to as a height-balanced binary tree.

Example:

Balanced and Unbalanced Binary Tree

Balanced and Unbalanced Binary Tree

It is a type of binary tree in which the difference between the height of the left and the right subtree for each node is either 0 or 1. In the figure above, the root node having a value 0 is unbalanced with a depth of 2 units.

Application of Balanced Binary Tree:

Advantages of Balanced Binary Tree:


Previous
Next
------

Preorder Traversal of Binary Tree

Preorder traversal is defined as a type of tree traversal that follows the Root-Left-Right policy where:

Preorder traversal

Preorder traversal

Algorithm for Preorder Traversal of Binary Tree

The algorithm for preorder traversal is shown as follows:

Preorder(root):

  1. Follow step 2 to 4 until root != NULL
  2. Write root -> data
  3. Preorder (root -> left)
  4. Preorder (root -> right)
  5. End loop

How does Preorder Traversal of Binary Tree work?

Consider the following tree:

Example of Binary Tree

Example of Binary Tree

If we perform a preorder traversal in this binary tree, then the traversal will be as follows:

Step 1: At first the root will be visited, i.e. node 1.

Node 1 is visited

Node 1 is visited

Step 2: After this, traverse in the left subtree. Now the root of the left subtree is visited i.e., node 2 is visited.

Node 2 is visited

Node 2 is visited

Step 3: Again the left subtree of node 2 is traversed and the root of that subtree i.e., node 4 is visited.

Node 4 is visited

Node 4 is visited

Step 4: There is no subtree of 4 and the left subtree of node 2 is visited. So now the right subtree of node 2 will be traversed and the root of that subtree i.e., node 5 will be visited.

Node 5 is visited

Node 5 is visited

Step 5: The left subtree of node 1 is visited. So now the right subtree of node 1 will be traversed and the root node i.e., node 3 is visited.

Node 3 is visited

Node 3 is visited

Step 6: Node 3 has no left subtree. So the right subtree will be traversed and the root of the subtree i.e., node 6 will be visited. After that there is no node that is not yet traversed. So the traversal ends.

The complete tree is visited

The complete tree is visited

So the order of traversal of nodes is 1 -> 2 -> 4 -> 5 -> 3 -> 6.

Program to Implement Preorder Traversal of Binary Tree

Below is the code implementation of the preorder traversal:

// C++ program for preorder traversals

#include <bits/stdc++.h>
using namespace std;

// Structure of a Binary Tree Node
struct Node {
    int data;
    struct Node *left, *right;
    Node(int v)
    {
        data = v;
        left = right = NULL;
    }
};

// Function to print preorder traversal
void printPreorder(struct Node* node)
{
    if (node == NULL)
        return;

    // Deal with the node
    cout << node->data << " ";

    // Recur on left subtree
    printPreorder(node->left);

    // Recur on right subtree
    printPreorder(node->right);
}

// Driver code
int main()
{
    struct Node* root = new Node(1);
    root->left = new Node(2);
    root->right = new Node(3);
    root->left->left = new Node(4);
    root->left->right = new Node(5);
    root->right->right = new Node(6);

    // Function call
    cout << "Preorder traversal of binary tree is: \n";
    printPreorder(root);

    return 0;
}
// Java program for preorder traversals

class Node {
    int data;
    Node left, right;

    public Node(int item) {
        data = item;
        left = right = null;
    }
}

class BinaryTree {
    Node root;

    BinaryTree() {
        root = null;
    }

    // Function to print preorder traversal
    void printPreorder(Node node) {
        if (node == null)
            return;

        // Deal with the node
        System.out.print(node.data + " ");

        // Recur on left subtree
        printPreorder(node.left);

        // Recur on right subtree
        printPreorder(node.right);
    }

    // Driver code
    public static void main(String[] args) {
        BinaryTree tree = new BinaryTree();

        // Constructing the binary tree
        tree.root = new Node(1);
        tree.root.left = new Node(2);
        tree.root.right = new Node(3);
        tree.root.left.left = new Node(4);
        tree.root.left.right = new Node(5);
        tree.root.right.right = new Node(6);

        // Function call
        System.out.println("Preorder traversal of binary tree is: ");
        tree.printPreorder(tree.root);
    }
}

Output
Preorder traversal of binary tree is: 
1 2 4 5 3 6 

Explanation:

How preorder traversal works

How preorder traversal works

Complexity Analysis:

Time Complexity: O(N) where N is the total number of nodes. Because it traverses all the nodes at least once.
Auxiliary Space: 

Use cases of Preorder Traversal:

Some use cases of preorder traversal are:

Related Articles:



Next
------

Inorder Traversal of Binary Tree

Inorder traversal is defined as a type of tree traversal technique which follows the Left-Root-Right pattern, such that:

Inorder traversal

Inorder traversal

Algorithm for Inorder Traversal of Binary Tree

The algorithm for inorder traversal is shown as follows:

Inorder(root):

  1. Follow step 2 to 4 until root != NULL
  2. Inorder (root -> left)
  3. Write root -> data
  4. Inorder (root -> right)
  5. End loop

How does Inorder Traversal of Binary Tree work?

Consider the following tree:

Example of Binary Tree

Example of Binary Tree

If we perform an inorder traversal in this binary tree, then the traversal will be as follows:

Step 1: The traversal will go from 1 to its left subtree i.e., 2, then from 2 to its left subtree root, i.e., 4. Now 4 has no left subtree, so it will be visited. It also does not have any right subtree. So no more traversal from 4

Node 4 is visited

Node 4 is visited

Step 2: As the left subtree of 2 is visited completely, now it read data of node 2 before moving to its right subtree.

Node 2 is visited

Node 2 is visited

Step 3: Now the right subtree of 2 will be traversed i.e., move to node 5. For node 5 there is no left subtree, so it gets visited and after that, the traversal comes back because there is no right subtree of node 5.

Node 5 is visited

Node 5 is visited

Step 4: As the left subtree of node 1 is, the root itself, i.e., node 1 will be visited.

Node 1 is visited

Node 1 is visited

Step 5: Left subtree of node 1 and the node itself is visited. So now the right subtree of 1 will be traversed i.e., move to node 3. As node 3 has no left subtree so it gets visited.

Node 3 is visited

Node 3 is visited

Step 6: The left subtree of node 3 and the node itself is visited. So traverse to the right subtree and visit node 6. Now the traversal ends as all the nodes are traversed.

The complete tree is traversed

The complete tree is traversed

So the order of traversal of nodes is 4 -> 2 -> 5 -> 1 -> 3 -> 6.

Program to implement Inorder Traversal of Binary Tree:

Below is the code implementation of the inorder traversal:

C++




// C++ program for inorder traversals
 
#include <bits/stdc++.h>
using namespace std;
 
// Structure of a Binary Tree Node
struct Node {
    int data;
    struct Node *left, *right;
    Node(int v)
    {
        data = v;
        left = right = NULL;
    }
};
 
// Function to print inorder traversal
void printInorder(struct Node* node)
{
    if (node == NULL)
        return;
 
    // First recur on left subtree
    printInorder(node->left);
 
    // Now deal with the node
    cout << node->data << " ";
 
    // Then recur on right subtree
    printInorder(node->right);
}
 
// Driver code
int main()
{
    struct Node* root = new Node(1);
    root->left = new Node(2);
    root->right = new Node(3);
    root->left->left = new Node(4);
    root->left->right = new Node(5);
    root->right->right = new Node(6);
 
    // Function call
    cout << "Inorder traversal of binary tree is: \n";
    printInorder(root);
 
    return 0;
}

Java




// Java program for inorder traversals
import java.util.*;
 
// Structure of a Binary Tree Node
class Node {
    int data;
    Node left, right;
 
    Node(int v)
    {
        data = v;
        left = right = null;
    }
}
 
// Main class
class GFG {
 
    // Function to print inorder traversal
    public static void printInorder(Node node)
    {
        if (node == null)
            return;
 
        // First recur on left subtree
        printInorder(node.left);
 
        // Now deal with the node
        System.out.print(node.data + " ");
 
        // Then recur on right subtree
        printInorder(node.right);
    }
 
    // Driver code
    public static void main(String[] args)
    {
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.left.left = new Node(4);
        root.left.right = new Node(5);
        root.right.right = new Node(6);
 
        // Function call
        System.out.println(
            "Inorder traversal of binary tree is: ");
        printInorder(root);
    }
}
// This code is contributed by prasad264

Python3




# Structure of a Binary Tree Node
class Node:
    def __init__(self, v):
        self.data = v
        self.left = None
        self.right = None
 
# Function to print inorder traversal
def printInorder(node):
    if node is None:
        return
 
    # First recur on left subtree
    printInorder(node.left)
 
    # Now deal with the node
    print(node.data, end=' ')
 
    # Then recur on right subtree
    printInorder(node.right)
 
# Driver code
if __name__ == '__main__':
    root = Node(1)
    root.left = Node(2)
    root.right = Node(3)
    root.left.left = Node(4)
    root.left.right = Node(5)
    root.right.right = Node(6)
 
    # Function call
    print("Inorder traversal of binary tree is:")
    printInorder(root)

C#




// C# program for inorder traversals
 
using System;
 
// Structure of a Binary Tree Node
public class Node {
    public int data;
    public Node left, right;
 
    public Node(int v)
    {
        data = v;
        left = right = null;
    }
}
 
// Class to store and print inorder traversal
public class BinaryTree {
    // Function to print inorder traversal
    public static void printInorder(Node node)
    {
        if (node == null)
            return;
 
        // First recur on left subtree
        printInorder(node.left);
 
        // Now deal with the node
        Console.Write(node.data + " ");
 
        // Then recur on right subtree
        printInorder(node.right);
    }
 
    // Driver code
    public static void Main()
    {
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.left.left = new Node(4);
        root.left.right = new Node(5);
        root.right.right = new Node(6);
 
        // Function call
        Console.WriteLine(
            "Inorder traversal of binary tree is: ");
        printInorder(root);
    }
}

Javascript




// JavaScript program for inorder traversals
 
// Structure of a Binary Tree Node
class Node {
    constructor(v) {
        this.data = v;
        this.left = null;
        this.right = null;
    }
}
 
// Function to print inorder traversal
function printInorder(node) {
    if (node === null) {
        return;
    }
     
    // First recur on left subtree
    printInorder(node.left);
     
    // Now deal with the node
    console.log(node.data);
     
    // Then recur on right subtree
    printInorder(node.right);
}
 
// Driver code
const root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.right = new Node(6);
 
// Function call
console.log("Inorder traversal of binary tree is: ");
printInorder(root);

Output
Inorder traversal of binary tree is: 
4 2 5 1 3 6 

Explanation:

How inorder traversal works

How inorder traversal works

Complexity Analysis:

Time Complexity: O(N) where N is the total number of nodes. Because it traverses all the nodes at least once.
Auxiliary Space: O(1) if no recursion stack space is considered. Otherwise, O(h) where h is the height of the tree

Use cases of Inorder Traversal:

In the case of BST (Binary Search Tree), if any time there is a need to get the nodes in non-decreasing order, the best way is to implement an inorder traversal.

Related Articles:



Next
------

Postorder Traversal of Binary Tree

Postorder traversal is defined as a type of tree traversal which follows the Left-Right-Root policy such that for each node:

Postorder traversal

Postorder traversal

Algorithm for Postorder Traversal of Binary Tree:

The algorithm for postorder traversal is shown as follows:

Postorder(root):

  1. Follow step 2 to 4 until root != NULL
  2. Postorder (root -> left)
  3. Postorder (root -> right)
  4. Write root -> data
  5. End loop

How does Postorder Traversal of Binary Tree Work?

Consider the following tree:

Example of Binary Tree

Example of Binary Tree

If we perform a postorder traversal in this binary tree, then the traversal will be as follows:

Step 1: The traversal will go from 1 to its left subtree i.e., 2, then from 2 to its left subtree root, i.e., 4. Now 4 has no subtree, so it will be visited.

Node 4 is visited

Node 4 is visited

Step 2: As the left subtree of 2 is visited completely, now it will traverse the right subtree of 2 i.e., it will move to 5. As there is no subtree of 5, it will be visited.

Node 5 is visited

Node 5 is visited

Step 3: Now both the left and right subtrees of node 2 are visited. So now visit node 2 itself.

Node 2 is visited

Node 2 is visited

Step 4: As the left subtree of node 1 is traversed, it will now move to the right subtree root, i.e., 3. Node 3 does not have any left subtree, so it will traverse the right subtree i.e., 6. Node 6 has no subtree and so it is visited.

Node 6 is visited

Node 6 is visited

Step 5: All the subtrees of node 3 are traversed. So now node 3 is visited.

Node 3 is visited

Node 3 is visited

Step 6: As all the subtrees of node 1 are traversed, now it is time for node 1 to be visited and the traversal ends after that as the whole tree is traversed.

The complete tree is visited

The complete tree is visited

So the order of traversal of nodes is 4 -> 5 -> 2 -> 6 -> 3 -> 1.

Program to implement Postorder Traversal of Binary Tree

Below is the code implementation of the postorder traversal:

C++




// C++ program for postorder traversals
 
#include <bits/stdc++.h>
using namespace std;
 
// Structure of a Binary Tree Node
struct Node {
    int data;
    struct Node *left, *right;
    Node(int v)
    {
        data = v;
        left = right = NULL;
    }
};
 
// Function to print postorder traversal
void printPostorder(struct Node* node)
{
    if (node == NULL)
        return;
 
    // First recur on left subtree
    printPostorder(node->left);
 
    // Then recur on right subtree
    printPostorder(node->right);
 
    // Now deal with the node
    cout << node->data << " ";
}
 
// Driver code
int main()
{
    struct Node* root = new Node(1);
    root->left = new Node(2);
    root->right = new Node(3);
    root->left->left = new Node(4);
    root->left->right = new Node(5);
    root->right->right = new Node(6);
 
    // Function call
    cout << "Postorder traversal of binary tree is: \n";
    printPostorder(root);
 
    return 0;
}

Java




// Java program for postorder traversals
import java.util.*;
 
// Structure of a Binary Tree Node
class Node {
    int data;
    Node left, right;
    Node(int v)
    {
        data = v;
        left = right = null;
    }
}
 
class GFG {
     
    // Function to print postorder traversal
    static void printPostorder(Node node)
    {
        if (node == null)
            return;
 
        // First recur on left subtree
        printPostorder(node.left);
 
        // Then recur on right subtree
        printPostorder(node.right);
 
        // Now deal with the node
        System.out.print(node.data + " ");
    }
 
    // Driver code
    public static void main(String[] args)
    {
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.left.left = new Node(4);
        root.left.right = new Node(5);
        root.right.right = new Node(6);
 
        // Function call
        System.out.println("Postorder traversal of binary tree is: ");
        printPostorder(root);
    }
}
// This code is contributed by prasad264

Python3




# Python program for postorder traversals
 
# Structure of a Binary Tree Node
 
 
class Node:
    def __init__(self, v):
        self.data = v
        self.left = None
        self.right = None
 
# Function to print postorder traversal
 
 
def printPostorder(node):
    if node == None:
        return
 
    # First recur on left subtree
    printPostorder(node.left)
 
    # Then recur on right subtree
    printPostorder(node.right)
 
    # Now deal with the node
    print(node.data, end=' ')
 
 
# Driver code
if __name__ == '__main__':
    root = Node(1)
    root.left = Node(2)
    root.right = Node(3)
    root.left.left = Node(4)
    root.left.right = Node(5)
    root.right.right = Node(6)
 
    # Function call
    print("Postorder traversal of binary tree is:")
    printPostorder(root)

C#




// C# program for postorder traversals
 
using System;
 
// Structure of a Binary Tree Node
public class Node {
    public int data;
    public Node left, right;
    public Node(int v)
    {
        data = v;
        left = right = null;
    }
}
 
public class GFG {
 
    // Function to print postorder traversal
    static void printPostorder(Node node)
    {
        if (node == null)
            return;
 
        // First recur on left subtree
        printPostorder(node.left);
 
        // Then recur on right subtree
        printPostorder(node.right);
 
        // Now deal with the node
        Console.Write(node.data + " ");
    }
 
    static public void Main()
    {
 
        // Code
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.left.left = new Node(4);
        root.left.right = new Node(5);
        root.right.right = new Node(6);
 
        // Function call
        Console.WriteLine(
            "Postorder traversal of binary tree is: ");
        printPostorder(root);
    }
}
 
// This code is contributed by karthik.

Javascript




// Structure of a Binary Tree Node
class Node {
  constructor(v) {
    this.data = v;
    this.left = null;
    this.right = null;
  }
}
 
// Function to print postorder traversal
function printPostorder(node) {
  if (node == null) {
    return;
  }
 
  // First recur on left subtree
  printPostorder(node.left);
 
  // Then recur on right subtree
  printPostorder(node.right);
 
  // Now deal with the node
  console.log(node.data + " ");
}
 
// Driver code
function main() {
  let root = new Node(1);
  root.left = new Node(2);
  root.right = new Node(3);
  root.left.left = new Node(4);
  root.left.right = new Node(5);
  root.right.right = new Node(6);
 
  // Function call
  console.log("Postorder traversal of binary tree is: \n");
  printPostorder(root);
}
 
main();

Output
Postorder traversal of binary tree is: 
4 5 2 6 3 1 

Explanation:

How postorder traversal works

How postorder traversal works

Complexity Analysis:

Time Complexity: O(N) where N is the total number of nodes. Because it traverses all the nodes at least once.
Auxiliary Space: O(1) if no recursion stack space is considered. Otherwise, O(h) where h is the height of the tree

Use cases of Postorder Traversal:

Some use cases of postorder traversal are:

Related articles:



Next
------

Level Order Traversal (Breadth First Search or BFS) of Binary Tree

Level Order Traversal technique is defined as a method to traverse a Tree such that all nodes present in the same level are traversed completely before traversing the next level.

BFS_1tree

Example:

Input:

Output:
1
2 3
4 5

Recommended Practice

How does Level Order Traversal work?

The main idea of level order traversal is to traverse all the nodes of a lower level before moving to any of the nodes of a higher level. This can be done in any of the following ways: 

Level Order Traversal (Naive approach):

Find height of tree. Then for each level, run a recursive function by maintaining current height. Whenever the level of a node matches, print that node.

Below is the implementation of the above approach:

// Recursive CPP program for level
// order traversal of Binary Tree
#include <bits/stdc++.h>
using namespace std;

// A binary tree node has data,
// pointer to left child
// and a pointer to right child
class node {
public:
    int data;
    node *left, *right;
};

// Function prototypes
void printCurrentLevel(node* root, int level);
int height(node* node);
node* newNode(int data);

// Function to print level order traversal a tree
void printLevelOrder(node* root)
{
    int h = height(root);
    int i;
    for (i = 1; i <= h; i++)
        printCurrentLevel(root, i);
}

// Print nodes at a current level
void printCurrentLevel(node* root, int level)
{
    if (root == NULL)
        return;
    if (level == 1)
        cout << root->data << " ";
    else if (level > 1) {
        printCurrentLevel(root->left, level - 1);
        printCurrentLevel(root->right, level - 1);
    }
}

// Compute the "height" of a tree -- the number of
// nodes along the longest path from the root node
// down to the farthest leaf node.
int height(node* node)
{
    if (node == NULL)
        return 0;
    else {
        
        // Compute the height of each subtree
        int lheight = height(node->left);
        int rheight = height(node->right);

        // Use the larger one
        if (lheight > rheight) {
            return (lheight + 1);
        }
        else {
            return (rheight + 1);
        }
    }
}

// Helper function that allocates
// a new node with the given data and
// NULL left and right pointers.
node* newNode(int data)
{
    node* Node = new node();
    Node->data = data;
    Node->left = NULL;
    Node->right = NULL;

    return (Node);
}

// Driver code
int main()
{
    node* root = newNode(1);
    root->left = newNode(2);
    root->right = newNode(3);
    root->left->left = newNode(4);
    root->left->right = newNode(5);

    cout << "Level Order traversal of binary tree is \n";
    printLevelOrder(root);

    return 0;
}

// This code is contributed by rathbhupendra
// Recursive Java program for level
// order traversal of Binary Tree

// 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;
    }
}

class BinaryTree {
    
    // Root of the Binary Tree
    Node root;

    public BinaryTree() { root = null; }

    // Function to print level order traversal of tree
    void printLevelOrder()
    {
        int h = height(root);
        int i;
        for (i = 1; i <= h; i++)
            printCurrentLevel(root, i);
    }

    // Compute the "height" of a tree -- the number of
    // nodes along the longest path from the root node
    // down to the farthest leaf node.
    int height(Node root)
    {
        if (root == null)
            return 0;
        else {
            
            // Compute  height of each subtree
            int lheight = height(root.left);
            int rheight = height(root.right);

            // use the larger one
            if (lheight > rheight)
                return (lheight + 1);
            else
                return (rheight + 1);
        }
    }

    // Print nodes at the current level
    void printCurrentLevel(Node root, int level)
    {
        if (root == null)
            return;
        if (level == 1)
            System.out.print(root.data + " ");
        else if (level > 1) {
            printCurrentLevel(root.left, level - 1);
            printCurrentLevel(root.right, level - 1);
        }
    }

    // Driver program to test above functions
    public static void main(String args[])
    {
        BinaryTree tree = new BinaryTree();
        tree.root = new Node(1);
        tree.root.left = new Node(2);
        tree.root.right = new Node(3);
        tree.root.left.left = new Node(4);
        tree.root.left.right = new Node(5);

        System.out.println("Level order traversal of"
                           + "binary tree is ");
        tree.printLevelOrder();
    }
}

Output
Level Order traversal of binary tree is 
1 2 3 4 5 

Time Complexity: O(N), where N is the number of nodes in the skewed tree.
Auxiliary Space: O(1) If the recursion stack is considered the space used is O(N).

Level Order Traversal using Queue

We need to visit the nodes in a lower level before any node in a higher level, this idea is quite similar to that of a queue. Push the nodes of a lower level in the queue. When any node is visited, pop that node from the queue and push the child of that node in the queue.

This ensures that the node of a lower level are visited prior to any node of a higher level.

Below is the Implementation of the above approach:

// C++ program to print level order traversal
#include <bits/stdc++.h>
using namespace std;

// A Binary Tree Node
struct Node {
    int data;
    struct Node *left, *right;
};

// Iterative method to find height of Binary Tree
void printLevelOrder(Node* root)
{
    // Base Case
    if (root == NULL)
        return;

    // Create an empty queue for level order traversal
    queue<Node*> q;

    // Enqueue Root and initialize height
    q.push(root);

    while (q.empty() == false) {
        
        // Print front of queue and remove it from queue
        Node* node = q.front();
        cout << node->data << " ";
        q.pop();

        // Enqueue left child
        if (node->left != NULL)
            q.push(node->left);

        // Enqueue right child
        if (node->right != NULL)
            q.push(node->right);
    }
}

// Utility function to create a new tree node
Node* newNode(int data)
{
    Node* temp = new Node;
    temp->data = data;
    temp->left = temp->right = NULL;
    return temp;
}

// Driver program to test above functions
int main()
{
    // Let us create binary tree shown in above diagram
    Node* root = newNode(1);
    root->left = newNode(2);
    root->right = newNode(3);
    root->left->left = newNode(4);
    root->left->right = newNode(5);

    cout << "Level Order traversal of binary tree is \n";
    printLevelOrder(root);
    return 0;
}
// Iterative Queue based Java program
// to do level order traversal
// of Binary Tree

import java.util.LinkedList;
import java.util.Queue;

// Class to represent Tree node
class Node {
    int data;
    Node left, right;

    public Node(int item)
    {
        data = item;
        left = null;
        right = null;
    }
}

// Class to print Level Order Traversal
class BinaryTree {

    Node root;

    // Given a binary tree. Print
    // its nodes in level order
    // using array for implementing queue
    void printLevelOrder()
    {
        Queue<Node> queue = new LinkedList<Node>();
        queue.add(root);
        while (!queue.isEmpty()) {

            // poll() removes the present head.  
            Node tempNode = queue.poll();
            System.out.print(tempNode.data + " ");

            // Enqueue left child
            if (tempNode.left != null) {
                queue.add(tempNode.left);
            }

            // Enqueue right child
            if (tempNode.right != null) {
                queue.add(tempNode.right);
            }
        }
    }

    public static void main(String args[])
    {
        // Creating a binary tree and entering
        // the nodes
        BinaryTree tree_level = new BinaryTree();
        tree_level.root = new Node(1);
        tree_level.root.left = new Node(2);
        tree_level.root.right = new Node(3);
        tree_level.root.left.left = new Node(4);
        tree_level.root.left.right = new Node(5);

        System.out.println("Level order traversal of binary tree is - ");
        tree_level.printLevelOrder();
    }
}

Output
Level Order traversal of binary tree is 
1 2 3 4 5 

Time Complexity: O(N) where N is the number of nodes in the binary tree.
Auxiliary Space: O(N) where N is the number of nodes in the binary tree.



Previous
Next
------

AVL Tree Data Structure

An AVL tree defined as a self-balancing Binary Search Tree (BST) where the difference between heights of left and right subtrees for any node cannot be more than one.

The difference between the heights of the left subtree and the right subtree for any node is known as the balance factor of the node.

The AVL tree is named after its inventors, Georgy Adelson-Velsky and Evgenii Landis, who published it in their 1962 paper “An algorithm for the organization of information”.

Example of AVL Trees:

AVL tree

AVL tree

The above tree is AVL because the differences between the heights of left and right subtrees for every node are less than or equal to 1.

Operations on an AVL Tree:

Rotating the subtrees in an AVL Tree:

An AVL tree may rotate in one of the following four ways to keep itself balanced:

Left Rotation:

When a node is added into the right subtree of the right subtree, if the tree gets out of balance, we do a single left rotation.

Left-Rotation in AVL tree

Right Rotation:

If a node is added to the left subtree of the left subtree, the AVL tree may get out of balance, we do a single right rotation.

avl-tree

Right-Rotation in AVL Tree

Left-Right Rotation:

A left-right rotation is a combination in which first left rotation takes place after that right rotation executes.

Left-Right Rotation in AVL tree

Right-Left Rotation:

A right-left rotation is a combination in which first right rotation takes place after that left rotation executes.

Right-Left Rotation in AVL tree

Applications of AVL Tree:

  1. It is used to index huge records in a database and also to efficiently search in that.
  2. For all types of in-memory collections, including sets and dictionaries, AVL Trees are used.
  3. Database applications, where insertions and deletions are less common but frequent data lookups are necessary
  4. Software that needs optimized search.
  5. It is applied in corporate areas and storyline games.

Advantages of AVL Tree:

  1. AVL trees can self-balance themselves.
  2. It is surely not skewed.
  3. It provides faster lookups than Red-Black Trees
  4. Better searching time complexity compared to other trees like binary tree.
  5. Height cannot exceed log(N), where, N is the total number of nodes in the tree.

Disadvantages of AVL Tree:

  1. It is difficult to implement.
  2. It has high constant factors for some of the operations.
  3. Less used compared to Red-Black trees.
  4. Due to its rather strict balance, AVL trees provide complicated insertion and removal operations as more rotations are performed.
  5. Take more processing for balancing.

Related Articles:


Next
------

Insertion in an AVL Tree

 AVL Tree:

AVL tree is a self-balancing Binary Search Tree (BST) where the difference between heights of left and right subtrees cannot be more than one for all nodes. 

Example of AVL Tree:
 

The above tree is AVL because the differences between the heights of left and right subtrees for every node are less than or equal to 1.

Example of a Tree that is NOT an AVL Tree:

The above tree is not AVL because the differences between the heights of the left and right subtrees for 8 and 12 are greater than 1.

Why AVL Trees? 

Most of the BST operations (e.g., search, max, min, insert, delete.. etc) take O(h) time where h is the height of the BST. The cost of these operations may become O(n) for a skewed Binary tree. If we make sure that the height of the tree remains O(log(n)) after every insertion and deletion, then we can guarantee an upper bound of O(log(n)) for all these operations. The height of an AVL tree is always O(log(n)) where n is the number of nodes in the tree.

Insertion in AVL Tree:

To make sure that the given tree remains AVL after every insertion, we must augment the standard BST insert operation to perform some re-balancing. 
Following are two basic operations that can be performed to balance a BST without violating the BST property (keys(left) < key(root) < keys(right)). 

T1, T2 and T3 are subtrees of the tree, rooted with y (on the left side) or x (on the right side)     
      
     y                               x
    / \     Right Rotation          /  \
   x   T3   - - - - - - - >        T1   y 
  / \       < - - - - - - -            / \
 T1  T2     Left Rotation            T2  T3
 
Keys in both of the above trees follow the following order 
keys(T1) < key(x) < keys(T2) < key(y) < keys(T3)
So BST property is not violated anywhere.
Recommended Practice

Steps to follow for insertion:

Let the newly inserted node be w 

Following are the operations to be performed in above mentioned 4 cases. In all of the cases, we only need to re-balance the subtree rooted with z and the complete tree becomes balanced as the height of the subtree (After appropriate rotations) rooted with z becomes the same as it was before insertion.

1. Left Left Case 

T1, T2, T3 and T4 are subtrees.
         z                                      y 
        / \                                   /   \
       y   T4      Right Rotate (z)          x      z
      / \          - - - - - - - - ->      /  \    /  \ 
     x   T3                               T1  T2  T3  T4
    / \
  T1   T2

2. Left Right Case 

     z                               z                           x
    / \                            /   \                        /  \ 
   y   T4  Left Rotate (y)        x    T4  Right Rotate(z)    y      z
  / \      - - - - - - - - ->    /  \      - - - - - - - ->  / \    / \
T1   x                          y    T3                    T1  T2 T3  T4
    / \                        / \
  T2   T3                    T1   T2

3. Right Right Case 

  z                                y
 /  \                            /   \ 
T1   y     Left Rotate(z)       z      x
    /  \   - - - - - - - ->    / \    / \
   T2   x                     T1  T2 T3  T4
       / \
     T3  T4

4. Right Left Case 

   z                            z                            x
  / \                          / \                          /  \ 
T1   y   Right Rotate (y)    T1   x      Left Rotate(z)   z      y
    / \  - - - - - - - - ->     /  \   - - - - - - - ->  / \    / \
   x   T4                      T2   y                  T1  T2  T3  T4
  / \                              /  \
T2   T3                           T3   T4

Illustration of Insertion at AVL Tree

avlinsert1

 

avlinsert2-jpg

 

avlinsert3

 

avlinsert4

 

avlinsert5

Approach:

The idea is to use recursive BST insert, after insertion, we get pointers to all ancestors one by one in a bottom-up manner. So we don’t need a parent pointer to travel up. The recursive code itself travels up and visits all the ancestors of the newly inserted node. 

Follow the steps mentioned below to implement the idea:

Below is the implementation of the above approach:

C++14




// C++ program to insert a node in AVL tree 
#include<bits/stdc++.h>
using namespace std;
  
// An AVL tree node 
class Node 
    public:
    int key; 
    Node *left; 
    Node *right; 
    int height; 
}; 
  
// A utility function to get the 
// height of the tree 
int height(Node *N) 
    if (N == NULL) 
        return 0; 
    return N->height; 
  
// A utility function to get maximum
// of two integers 
int max(int a, int b) 
    return (a > b)? a : b; 
  
/* Helper function that allocates a 
   new node with the given key and 
   NULL left and right pointers. */
Node* newNode(int key) 
    Node* node = new Node();
    node->key = key; 
    node->left = NULL; 
    node->right = NULL; 
    node->height = 1; // new node is initially
                      // added at leaf 
    return(node); 
  
// A utility function to right
// rotate subtree rooted with y 
// See the diagram given above. 
Node *rightRotate(Node *y) 
    Node *x = y->left; 
    Node *T2 = x->right; 
  
    // Perform rotation 
    x->right = y; 
    y->left = T2; 
  
    // Update heights 
    y->height = max(height(y->left),
                    height(y->right)) + 1; 
    x->height = max(height(x->left),
                    height(x->right)) + 1; 
  
    // Return new root 
    return x; 
  
// A utility function to left 
// rotate subtree rooted with x 
// See the diagram given above. 
Node *leftRotate(Node *x) 
    Node *y = x->right; 
    Node *T2 = y->left; 
  
    // Perform rotation 
    y->left = x; 
    x->right = T2; 
  
    // Update heights 
    x->height = max(height(x->left),    
                    height(x->right)) + 1; 
    y->height = max(height(y->left), 
                    height(y->right)) + 1; 
  
    // Return new root 
    return y; 
  
// Get Balance factor of node N 
int getBalance(Node *N) 
    if (N == NULL) 
        return 0; 
    return height(N->left) - height(N->right); 
  
// Recursive function to insert a key
// in the subtree rooted with node and
// returns the new root of the subtree. 
Node* insert(Node* node, int key) 
    /* 1. Perform the normal BST insertion */
    if (node == NULL) 
        return(newNode(key)); 
  
    if (key < node->key) 
        node->left = insert(node->left, key); 
    else if (key > node->key) 
        node->right = insert(node->right, key); 
    else // Equal keys are not allowed in BST 
        return node; 
  
    /* 2. Update height of this ancestor node */
    node->height = 1 + max(height(node->left), 
                        height(node->right)); 
  
    /* 3. Get the balance factor of this ancestor 
        node to check whether this node became 
        unbalanced */
    int balance = getBalance(node); 
  
    // If this node becomes unbalanced, then 
    // there are 4 cases 
  
    // Left Left Case 
    if (balance > 1 && key < node->left->key) 
        return rightRotate(node); 
  
    // Right Right Case 
    if (balance < -1 && key > node->right->key) 
        return leftRotate(node); 
  
    // Left Right Case 
    if (balance > 1 && key > node->left->key) 
    
        node->left = leftRotate(node->left); 
        return rightRotate(node); 
    
  
    // Right Left Case 
    if (balance < -1 && key < node->right->key) 
    
        node->right = rightRotate(node->right); 
        return leftRotate(node); 
    
  
    /* return the (unchanged) node pointer */
    return node; 
  
// A utility function to print preorder 
// traversal of the tree. 
// The function also prints height 
// of every node 
void preOrder(Node *root) 
    if(root != NULL) 
    
        cout << root->key << " "
        preOrder(root->left); 
        preOrder(root->right); 
    
  
// Driver Code
int main() 
    Node *root = NULL; 
      
    /* Constructing tree given in 
    the above figure */
    root = insert(root, 10); 
    root = insert(root, 20); 
    root = insert(root, 30); 
    root = insert(root, 40); 
    root = insert(root, 50); 
    root = insert(root, 25); 
      
    /* The constructed AVL Tree would be 
                30 
            / \ 
            20 40 
            / \ \ 
        10 25 50 
    */
    cout << "Preorder traversal of the "
            "constructed AVL tree is \n"
    preOrder(root); 
      
    return 0; 
  
// This code is contributed by
// rathbhupendra

C




// C program to insert a node in AVL tree
#include<stdio.h>
#include<stdlib.h>
  
// An AVL tree node
struct Node
{
    int key;
    struct Node *left;
    struct Node *right;
    int height;
};
  
// A utility function to get the height of the tree
int height(struct Node *N)
{
    if (N == NULL)
        return 0;
    return N->height;
}
  
// A utility function to get maximum of two integers
int max(int a, int b)
{
    return (a > b)? a : b;
}
  
/* Helper function that allocates a new node with the given key and
    NULL left and right pointers. */
struct Node* newNode(int key)
{
    struct Node* node = (struct Node*)
                        malloc(sizeof(struct Node));
    node->key   = key;
    node->left   = NULL;
    node->right  = NULL;
    node->height = 1;  // new node is initially added at leaf
    return(node);
}
  
// A utility function to right rotate subtree rooted with y
// See the diagram given above.
struct Node *rightRotate(struct Node *y)
{
    struct Node *x = y->left;
    struct Node *T2 = x->right;
  
    // Perform rotation
    x->right = y;
    y->left = T2;
  
    // Update heights
    y->height = max(height(y->left),
                    height(y->right)) + 1;
    x->height = max(height(x->left),
                    height(x->right)) + 1;
  
    // Return new root
    return x;
}
  
// A utility function to left rotate subtree rooted with x
// See the diagram given above.
struct Node *leftRotate(struct Node *x)
{
    struct Node *y = x->right;
    struct Node *T2 = y->left;
  
    // Perform rotation
    y->left = x;
    x->right = T2;
  
    //  Update heights
    x->height = max(height(x->left),   
                    height(x->right)) + 1;
    y->height = max(height(y->left),
                    height(y->right)) + 1;
  
    // Return new root
    return y;
}
  
// Get Balance factor of node N
int getBalance(struct Node *N)
{
    if (N == NULL)
        return 0;
    return height(N->left) - height(N->right);
}
  
// Recursive function to insert a key in the subtree rooted
// with node and returns the new root of the subtree.
struct Node* insert(struct Node* node, int key)
{
    /* 1.  Perform the normal BST insertion */
    if (node == NULL)
        return(newNode(key));
  
    if (key < node->key)
        node->left  = insert(node->left, key);
    else if (key > node->key)
        node->right = insert(node->right, key);
    else // Equal keys are not allowed in BST
        return node;
  
    /* 2. Update height of this ancestor node */
    node->height = 1 + max(height(node->left),
                        height(node->right));
  
    /* 3. Get the balance factor of this ancestor
          node to check whether this node became
          unbalanced */
    int balance = getBalance(node);
  
    // If this node becomes unbalanced, then
    // there are 4 cases
  
    // Left Left Case
    if (balance > 1 && key < node->left->key)
        return rightRotate(node);
  
    // Right Right Case
    if (balance < -1 && key > node->right->key)
        return leftRotate(node);
  
    // Left Right Case
    if (balance > 1 && key > node->left->key)
    {
        node->left =  leftRotate(node->left);
        return rightRotate(node);
    }
  
    // Right Left Case
    if (balance < -1 && key < node->right->key)
    {
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }
  
    /* return the (unchanged) node pointer */
    return node;
}
  
// A utility function to print preorder traversal
// of the tree.
// The function also prints height of every node
void preOrder(struct Node *root)
{
    if(root != NULL)
    {
        printf("%d ", root->key);
        preOrder(root->left);
        preOrder(root->right);
    }
}
  
/* Driver program to test above function*/
int main()
{
  struct Node *root = NULL;
  
  /* Constructing tree given in the above figure */
  root = insert(root, 10);
  root = insert(root, 20);
  root = insert(root, 30);
  root = insert(root, 40);
  root = insert(root, 50);
  root = insert(root, 25);
  
  /* The constructed AVL Tree would be
            30
           /  \
         20   40
        /  \     \
       10  25    50
  */
  
  printf("Preorder traversal of the constructed AVL"
         " tree is \n");
  preOrder(root);
  
  return 0;
}

Java




// Java program for insertion in AVL Tree
class Node {
    int key, height;
    Node left, right;
  
    Node(int d) {
        key = d;
        height = 1;
    }
}
  
class AVLTree {
  
    Node root;
  
    // A utility function to get the height of the tree
    int height(Node N) {
        if (N == null)
            return 0;
  
        return N.height;
    }
  
    // A utility function to get maximum of two integers
    int max(int a, int b) {
        return (a > b) ? a : b;
    }
  
    // A utility function to right rotate subtree rooted with y
    // See the diagram given above.
    Node rightRotate(Node y) {
        Node x = y.left;
        Node T2 = x.right;
  
        // Perform rotation
        x.right = y;
        y.left = T2;
  
        // Update heights
        y.height = max(height(y.left), height(y.right)) + 1;
        x.height = max(height(x.left), height(x.right)) + 1;
  
        // Return new root
        return x;
    }
  
    // A utility function to left rotate subtree rooted with x
    // See the diagram given above.
    Node leftRotate(Node x) {
        Node y = x.right;
        Node T2 = y.left;
  
        // Perform rotation
        y.left = x;
        x.right = T2;
  
        //  Update heights
        x.height = max(height(x.left), height(x.right)) + 1;
        y.height = max(height(y.left), height(y.right)) + 1;
  
        // Return new root
        return y;
    }
  
    // Get Balance factor of node N
    int getBalance(Node N) {
        if (N == null)
            return 0;
  
        return height(N.left) - height(N.right);
    }
  
    Node insert(Node node, int key) {
  
        /* 1.  Perform the normal BST insertion */
        if (node == null)
            return (new Node(key));
  
        if (key < node.key)
            node.left = insert(node.left, key);
        else if (key > node.key)
            node.right = insert(node.right, key);
        else // Duplicate keys not allowed
            return node;
  
        /* 2. Update height of this ancestor node */
        node.height = 1 + max(height(node.left),
                              height(node.right));
  
        /* 3. Get the balance factor of this ancestor
              node to check whether this node became
              unbalanced */
        int balance = getBalance(node);
  
        // If this node becomes unbalanced, then there
        // are 4 cases Left Left Case
        if (balance > 1 && key < node.left.key)
            return rightRotate(node);
  
        // Right Right Case
        if (balance < -1 && key > node.right.key)
            return leftRotate(node);
  
        // Left Right Case
        if (balance > 1 && key > node.left.key) {
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }
  
        // Right Left Case
        if (balance < -1 && key < node.right.key) {
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }
  
        /* return the (unchanged) node pointer */
        return node;
    }
  
    // A utility function to print preorder traversal
    // of the tree.
    // The function also prints height of every node
    void preOrder(Node node) {
        if (node != null) {
            System.out.print(node.key + " ");
            preOrder(node.left);
            preOrder(node.right);
        }
    }
  
    public static void main(String[] args) {
        AVLTree tree = new AVLTree();
  
        /* Constructing tree given in the above figure */
        tree.root = tree.insert(tree.root, 10);
        tree.root = tree.insert(tree.root, 20);
        tree.root = tree.insert(tree.root, 30);
        tree.root = tree.insert(tree.root, 40);
        tree.root = tree.insert(tree.root, 50);
        tree.root = tree.insert(tree.root, 25);
  
        /* The constructed AVL Tree would be
             30
            /  \
          20   40
         /  \     \
        10  25    50
        */
        System.out.println("Preorder traversal" +
                        " of constructed tree is : ");
        tree.preOrder(tree.root);
    }
}
// This code has been contributed by Mayank Jaiswal

Python3




# Python code to insert a node in AVL tree
  
# Generic tree node class
class TreeNode(object):
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None
        self.height = 1
  
# AVL tree class which supports the 
# Insert operation
class AVL_Tree(object):
  
    # Recursive function to insert key in 
    # subtree rooted with node and returns
    # new root of subtree.
    def insert(self, root, key):
      
        # Step 1 - Perform normal BST
        if not root:
            return TreeNode(key)
        elif key < root.val:
            root.left = self.insert(root.left, key)
        else:
            root.right = self.insert(root.right, key)
  
        # Step 2 - Update the height of the 
        # ancestor node
        root.height = 1 + max(self.getHeight(root.left),
                           self.getHeight(root.right))
  
        # Step 3 - Get the balance factor
        balance = self.getBalance(root)
  
        # Step 4 - If the node is unbalanced, 
        # then try out the 4 cases
        # Case 1 - Left Left
        if balance > 1 and key < root.left.val:
            return self.rightRotate(root)
  
        # Case 2 - Right Right
        if balance < -1 and key > root.right.val:
            return self.leftRotate(root)
  
        # Case 3 - Left Right
        if balance > 1 and key > root.left.val:
            root.left = self.leftRotate(root.left)
            return self.rightRotate(root)
  
        # Case 4 - Right Left
        if balance < -1 and key < root.right.val:
            root.right = self.rightRotate(root.right)
            return self.leftRotate(root)
  
        return root
  
    def leftRotate(self, z):
  
        y = z.right
        T2 = y.left
  
        # Perform rotation
        y.left = z
        z.right = T2
  
        # Update heights
        z.height = 1 + max(self.getHeight(z.left),
                         self.getHeight(z.right))
        y.height = 1 + max(self.getHeight(y.left),
                         self.getHeight(y.right))
  
        # Return the new root
        return y
  
    def rightRotate(self, z):
  
        y = z.left
        T3 = y.right
  
        # Perform rotation
        y.right = z
        z.left = T3
  
        # Update heights
        z.height = 1 + max(self.getHeight(z.left),
                        self.getHeight(z.right))
        y.height = 1 + max(self.getHeight(y.left),
                        self.getHeight(y.right))
  
        # Return the new root
        return y
  
    def getHeight(self, root):
        if not root:
            return 0
  
        return root.height
  
    def getBalance(self, root):
        if not root:
            return 0
  
        return self.getHeight(root.left) - self.getHeight(root.right)
  
    def preOrder(self, root):
  
        if not root:
            return
  
        print("{0} ".format(root.val), end="")
        self.preOrder(root.left)
        self.preOrder(root.right)
  
  
# Driver program to test above function
myTree = AVL_Tree()
root = None
  
root = myTree.insert(root, 10)
root = myTree.insert(root, 20)
root = myTree.insert(root, 30)
root = myTree.insert(root, 40)
root = myTree.insert(root, 50)
root = myTree.insert(root, 25)
  
"""The constructed AVL Tree would be
            30
           /  \
         20   40
        /  \     \
       10  25    50"""
  
# Preorder Traversal
print("Preorder traversal of the",
      "constructed AVL tree is")
myTree.preOrder(root)
print()
  
# This code is contributed by Ajitesh Pathak

C#




// C# program for insertion in AVL Tree 
using System;
  
class Node 
    public int key, height; 
    public Node left, right; 
  
    public Node(int d)
    
        key = d; 
        height = 1; 
    
  
public class AVLTree 
  
    Node root; 
  
    // A utility function to get
    // the height of the tree 
    int height(Node N) 
    
        if (N == null
            return 0; 
  
        return N.height; 
    
  
    // A utility function to get
    // maximum of two integers 
    int max(int a, int b) 
    
        return (a > b) ? a : b; 
    
  
    // A utility function to right 
    // rotate subtree rooted with y 
    // See the diagram given above. 
    Node rightRotate(Node y) 
    
        Node x = y.left; 
        Node T2 = x.right; 
  
        // Perform rotation 
        x.right = y; 
        y.left = T2; 
  
        // Update heights 
        y.height = max(height(y.left),
                    height(y.right)) + 1; 
        x.height = max(height(x.left),
                    height(x.right)) + 1; 
  
        // Return new root 
        return x; 
    
  
    // A utility function to left
    // rotate subtree rooted with x 
    // See the diagram given above. 
    Node leftRotate(Node x) 
    
        Node y = x.right; 
        Node T2 = y.left; 
  
        // Perform rotation 
        y.left = x; 
        x.right = T2; 
  
        // Update heights 
        x.height = max(height(x.left), 
                    height(x.right)) + 1; 
        y.height = max(height(y.left), 
                    height(y.right)) + 1; 
  
        // Return new root 
        return y; 
    
  
    // Get Balance factor of node N 
    int getBalance(Node N)
    
        if (N == null
            return 0; 
  
        return height(N.left) - height(N.right); 
    
  
    Node insert(Node node, int key) 
    
  
        /* 1. Perform the normal BST insertion */
        if (node == null
            return (new Node(key)); 
  
        if (key < node.key) 
            node.left = insert(node.left, key); 
        else if (key > node.key) 
            node.right = insert(node.right, key); 
        else // Duplicate keys not allowed 
            return node; 
  
        /* 2. Update height of this ancestor node */
        node.height = 1 + max(height(node.left), 
                            height(node.right)); 
  
        /* 3. Get the balance factor of this ancestor 
            node to check whether this node became 
            unbalanced */
        int balance = getBalance(node); 
  
        // If this node becomes unbalanced, then there 
        // are 4 cases Left Left Case 
        if (balance > 1 && key < node.left.key) 
            return rightRotate(node); 
  
        // Right Right Case 
        if (balance < -1 && key > node.right.key) 
            return leftRotate(node); 
  
        // Left Right Case 
        if (balance > 1 && key > node.left.key) 
        
            node.left = leftRotate(node.left); 
            return rightRotate(node); 
        
  
        // Right Left Case 
        if (balance < -1 && key < node.right.key) 
        
            node.right = rightRotate(node.right); 
            return leftRotate(node); 
        
  
        /* return the (unchanged) node pointer */
        return node; 
    
  
    // A utility function to print preorder traversal 
    // of the tree. 
    // The function also prints height of every node 
    void preOrder(Node node) 
    
        if (node != null)
        
            Console.Write(node.key + " "); 
            preOrder(node.left); 
            preOrder(node.right); 
        
    
  
    // Driver code
    public static void Main(String[] args) 
    
        AVLTree tree = new AVLTree(); 
  
        /* Constructing tree given in the above figure */
        tree.root = tree.insert(tree.root, 10); 
        tree.root = tree.insert(tree.root, 20); 
        tree.root = tree.insert(tree.root, 30); 
        tree.root = tree.insert(tree.root, 40); 
        tree.root = tree.insert(tree.root, 50); 
        tree.root = tree.insert(tree.root, 25); 
  
        /* The constructed AVL Tree would be 
            30 
            / \ 
        20 40 
        / \ \ 
        10 25 50 
        */
        Console.Write("Preorder traversal"
                        " of constructed tree is : "); 
        tree.preOrder(tree.root); 
    
  
// This code has been contributed
// by PrinciRaj1992

Javascript




<script>
  
      // JavaScript program for insertion in AVL Tree
      class Node {
        constructor(d) {
          this.key = d;
          this.height = 1;
          this.left = null;
          this.right = null;
        }
      }
  
      class AVLTree {
        constructor() {
          this.root = null;
        }
  
        // A utility function to get
        // the height of the tree
        height(N) {
          if (N == null) return 0;
  
          return N.height;
        }
  
        // A utility function to get
        // maximum of two integers
        max(a, b) {
          return a > b ? a : b;
        }
  
        // A utility function to right
        // rotate subtree rooted with y
        // See the diagram given above.
        rightRotate(y) {
          var x = y.left;
          var T2 = x.right;
  
          // Perform rotation
          x.right = y;
          y.left = T2;
  
          // Update heights
          y.height = this.max(this.height(y.left), 
          this.height(y.right)) + 1;
          x.height = this.max(this.height(x.left), 
          this.height(x.right)) + 1;
  
          // Return new root
          return x;
        }
  
        // A utility function to left
        // rotate subtree rooted with x
        // See the diagram given above.
        leftRotate(x) {
          var y = x.right;
          var T2 = y.left;
  
          // Perform rotation
          y.left = x;
          x.right = T2;
  
          // Update heights
          x.height = this.max(this.height(x.left), 
          this.height(x.right)) + 1;
          y.height = this.max(this.height(y.left), 
          this.height(y.right)) + 1;
  
          // Return new root
          return y;
        }
  
        // Get Balance factor of node N
        getBalance(N) {
          if (N == null) return 0;
  
          return this.height(N.left) - this.height(N.right);
        }
  
        insert(node, key) {
          /* 1. Perform the normal BST insertion */
          if (node == null) return new Node(key);
  
          if (key < node.key) 
          node.left = this.insert(node.left, key);
          else if (key > node.key) 
          node.right = this.insert(node.right, key);
          // Duplicate keys not allowed
          else return node;
  
          /* 2. Update height of this ancestor node */
          node.height =
            1 + this.max(this.height(node.left),
                this.height(node.right));
  
          /* 3. Get the balance factor of this ancestor
            node to check whether this node became
            unbalanced */
          var balance = this.getBalance(node);
  
          // If this node becomes unbalanced, then there
          // are 4 cases Left Left Case
          if (balance > 1 && key < node.left.key)
          return this.rightRotate(node);
  
          // Right Right Case
          if (balance < -1 && key > node.right.key)
            return this.leftRotate(node);
  
          // Left Right Case
          if (balance > 1 && key > node.left.key) {
            node.left = this.leftRotate(node.left);
            return this.rightRotate(node);
          }
  
          // Right Left Case
          if (balance < -1 && key < node.right.key) {
            node.right = this.rightRotate(node.right);
            return this.leftRotate(node);
          }
  
          /* return the (unchanged) node pointer */
          return node;
        }
  
        // A utility function to print preorder traversal
        // of the tree.
        // The function also prints height of every node
        preOrder(node) {
          if (node != null) {
            document.write(node.key + " ");
            this.preOrder(node.left);
            this.preOrder(node.right);
          }
        }
      }
      // Driver code
      var tree = new AVLTree();
  
      /* Constructing tree given in the above figure */
      tree.root = tree.insert(tree.root, 10);
      tree.root = tree.insert(tree.root, 20);
      tree.root = tree.insert(tree.root, 30);
      tree.root = tree.insert(tree.root, 40);
      tree.root = tree.insert(tree.root, 50);
      tree.root = tree.insert(tree.root, 25);
  
      /* The constructed AVL Tree would be
            30
            / \
           20 40
          / \   \
         10 25  50
        */
      document.write(
      "Preorder traversal of the " + "constructed AVL tree is <br>"
      );
      tree.preOrder(tree.root);
        
</script>

Output
Preorder traversal of the constructed AVL tree is 
30 20 10 25 40 50 

Complexity Analysis

Time Complexity: O(log(n)), For Insertion
Auxiliary Space: O(1)

The rotation operations (left and right rotate) take constant time as only a few pointers are being changed there. Updating the height and getting the balance factor also takes constant time. So the time complexity of the AVL insert remains the same as the BST insert which is O(h) where h is the height of the tree. Since the AVL tree is balanced, the height is O(Logn). So time complexity of AVL insert is O(Logn).

Comparison with Red Black Tree:

The AVL tree and other self-balancing search trees like Red Black are useful to get all basic operations done in O(log n) time. The AVL trees are more balanced compared to Red-Black Trees, but they may cause more rotations during insertion and deletion. So if your application involves many frequent insertions and deletions, then Red Black trees should be preferred. And if the insertions and deletions are less frequent and search is the more frequent operation, then the AVL tree should be preferred over Red Black Tree.

Following is the post for deletion in AVL Tree:
AVL Tree | Set 2 (Deletion)



Previous
Next
------

Deletion in an AVL Tree

 

We have discussed AVL insertion in the previous post. In this post, we will follow a similar approach for deletion.

Steps to follow for deletion
To make sure that the given tree remains AVL after every deletion, we must augment the standard BST delete operation to perform some re-balancing. Following are two basic operations that can be performed to re-balance a BST without violating the BST property (keys(left) < key(root) < keys(right)). 

  1. Left Rotation 
  2. Right Rotation 
T1, T2 and T3 are subtrees of the tree rooted with y (on left side)
or x (on right side)
                y                               x
               / \     Right Rotation          /  \
              x   T3   – - – - – - – >        T1   y
             / \       < - - - - - - -            / \
            T1  T2     Left Rotation            T2  T3
Keys in both of the above trees follow the following order
      keys(T1) < key(x) < keys(T2) < key(y) < keys(T3)
So BST property is not violated anywhere.

Let w be the node to be deleted 

  1. Perform standard BST delete for w. 
  2. Starting from w, travel up and find the first unbalanced node. Let z be the first unbalanced node, y be the larger height child of z, and x be the larger height child of y. Note that the definitions of x and y are different from insertion here. 
  3. Re-balance the tree by performing appropriate rotations on the subtree rooted with z. There can be 4 possible cases that needs to be handled as x, y and z can be arranged in 4 ways. Following are the possible 4 arrangements: 
    1. y is left child of z and x is left child of y (Left Left Case) 
    2. y is left child of z and x is right child of y (Left Right Case) 
    3. y is right child of z and x is right child of y (Right Right Case) 
    4. y is right child of z and x is left child of y (Right Left Case)

Like insertion, following are the operations to be performed in above mentioned 4 cases. Note that, unlike insertion, fixing the node z won’t fix the complete AVL tree. After fixing z, we may have to fix ancestors of z as well (See this video lecture for proof)

a) Left Left Case 

T1, T2, T3 and T4 are subtrees.
         z                                      y 
        / \                                   /   \
       y   T4      Right Rotate (z)          x      z
      / \          - - - - - - - - ->      /  \    /  \ 
     x   T3                               T1  T2  T3  T4
    / \
  T1   T2

b) Left Right Case 

     z                               z                           x
    / \                            /   \                        /  \ 
   y   T4  Left Rotate (y)        x    T4  Right Rotate(z)    y      z
  / \      - - - - - - - - ->    /  \      - - - - - - - ->  / \    / \
T1   x                          y    T3                    T1  T2 T3  T4
    / \                        / \
  T2   T3                    T1   T2

c) Right Right Case 

  z                                y
 /  \                            /   \ 
T1   y     Left Rotate(z)       z      x
    /  \   - - - - - - - ->    / \    / \
   T2   x                     T1  T2 T3  T4
       / \
     T3  T4

d) Right Left Case 

   z                            z                            x
  / \                          / \                          /  \ 
T1   y   Right Rotate (y)    T1   x      Left Rotate(z)   z      y
    / \  - - - - - - - - ->     /  \   - - - - - - - ->  / \    / \
   x   T4                      T2   y                  T1  T2  T3  T4
  / \                              /  \
T2   T3                           T3   T4

Unlike insertion, in deletion, after we perform a rotation at z, we may have to perform a rotation at ancestors of z. Thus, we must continue to trace the path until we reach the root.

Example:  

avl-delete1avl-delete1

A node with value 32 is being deleted. After deleting 32, we travel up and find the first unbalanced node which is 44. We mark it as z, its higher height child as y which is 62, and y’s higher height child as x which could be either 78 or 50 as both are of same height. We have considered 78. Now the case is Right Right, so we perform left rotation.

Recommended Practice

C implementation 
Following is the C implementation for AVL Tree Deletion. The following C implementation uses the recursive BST delete as basis. In the recursive BST delete, after deletion, we get pointers to all ancestors one by one in bottom up manner. So we don’t need parent pointer to travel up. The recursive code itself travels up and visits all the ancestors of the deleted node. 

  1. Perform the normal BST deletion. 
  2. The current node must be one of the ancestors of the deleted node. Update the height of the current node. 
  3. Get the balance factor (left subtree height – right subtree height) of the current node. 
  4. If balance factor is greater than 1, then the current node is unbalanced and we are either in Left Left case or Left Right case. To check whether it is Left Left case or Left Right case, get the balance factor of left subtree. If balance factor of the left subtree is greater than or equal to 0, then it is Left Left case, else Left Right case. 
  5. If balance factor is less than -1, then the current node is unbalanced and we are either in Right Right case or Right Left case. To check whether it is Right Right case or Right Left case, get the balance factor of right subtree. If the balance factor of the right subtree is smaller than or equal to 0, then it is Right Right case, else Right Left case.

C++




// C++ program to delete a node from AVL Tree
#include<bits/stdc++.h>
using namespace std;
 
// An AVL tree node
class Node
{
    public:
    int key;
    Node *left;
    Node *right;
    int height;
};
 
// A utility function to get maximum
// of two integers
int max(int a, int b);
 
// A utility function to get height
// of the tree
int height(Node *N)
{
    if (N == NULL)
        return 0;
    return N->height;
}
 
// A utility function to get maximum
// of two integers
int max(int a, int b)
{
    return (a > b)? a : b;
}
 
/* Helper function that allocates a
   new node with the given key and
   NULL left and right pointers. */
Node* newNode(int key)
{
    Node* node = new Node();
    node->key = key;
    node->left = NULL;
    node->right = NULL;
    node->height = 1; // new node is initially
                      // added at leaf
    return(node);
}
 
// A utility function to right
// rotate subtree rooted with y
// See the diagram given above.
Node *rightRotate(Node *y)
{
    Node *x = y->left;
    Node *T2 = x->right;
 
    // Perform rotation
    x->right = y;
    y->left = T2;
 
    // Update heights
    y->height = max(height(y->left),
                    height(y->right)) + 1;
    x->height = max(height(x->left),
                    height(x->right)) + 1;
 
    // Return new root
    return x;
}
 
// A utility function to left
// rotate subtree rooted with x
// See the diagram given above.
Node *leftRotate(Node *x)
{
    Node *y = x->right;
    Node *T2 = y->left;
 
    // Perform rotation
    y->left = x;
    x->right = T2;
 
    // Update heights
    x->height = max(height(x->left),
                    height(x->right)) + 1;
    y->height = max(height(y->left),
                    height(y->right)) + 1;
 
    // Return new root
    return y;
}
 
// Get Balance factor of node N
int getBalance(Node *N)
{
    if (N == NULL)
        return 0;
    return height(N->left) -
           height(N->right);
}
 
Node* insert(Node* node, int key)
{
    /* 1. Perform the normal BST rotation */
    if (node == NULL)
        return(newNode(key));
 
    if (key < node->key)
        node->left = insert(node->left, key);
    else if (key > node->key)
        node->right = insert(node->right, key);
    else // Equal keys not allowed
        return node;
 
    /* 2. Update height of this ancestor node */
    node->height = 1 + max(height(node->left),
                           height(node->right));
 
    /* 3. Get the balance factor of this
        ancestor node to check whether
        this node became unbalanced */
    int balance = getBalance(node);
 
    // If this node becomes unbalanced,
    // then there are 4 cases
 
    // Left Left Case
    if (balance > 1 && key < node->left->key)
        return rightRotate(node);
 
    // Right Right Case
    if (balance < -1 && key > node->right->key)
        return leftRotate(node);
 
    // Left Right Case
    if (balance > 1 && key > node->left->key)
    {
        node->left = leftRotate(node->left);
        return rightRotate(node);
    }
 
    // Right Left Case
    if (balance < -1 && key < node->right->key)
    {
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }
 
    /* return the (unchanged) node pointer */
    return node;
}
 
/* Given a non-empty binary search tree,
return the node with minimum key value
found in that tree. Note that the entire
tree does not need to be searched. */
Node * minValueNode(Node* node)
{
    Node* current = node;
 
    /* loop down to find the leftmost leaf */
    while (current->left != NULL)
        current = current->left;
 
    return current;
}
 
// Recursive function to delete a node
// with given key from subtree with
// given root. It returns root of the
// modified subtree.
Node* deleteNode(Node* root, int key)
{
     
    // STEP 1: PERFORM STANDARD BST DELETE
    if (root == NULL)
        return root;
 
    // If the key to be deleted is smaller
    // than the root's key, then it lies
    // in left subtree
    if ( key < root->key )
        root->left = deleteNode(root->left, key);
 
    // If the key to be deleted is greater
    // than the root's key, then it lies
    // in right subtree
    else if( key > root->key )
        root->right = deleteNode(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) ||
            (root->right == NULL) )
        {
            Node *temp = root->left ?
                         root->left :
                         root->right;
 
            // No child case
            if (temp == NULL)
            {
                temp = root;
                root = NULL;
            }
            else // One child case
            *root = *temp; // Copy the contents of
                           // the non-empty child
            free(temp);
        }
        else
        {
            // node with two children: Get the inorder
            // successor (smallest in the right subtree)
            Node* temp = minValueNode(root->right);
 
            // Copy the inorder successor's
            // data to this node
            root->key = temp->key;
 
            // Delete the inorder successor
            root->right = deleteNode(root->right,
                                     temp->key);
        }
    }
 
    // If the tree had only one node
    // then return
    if (root == NULL)
    return root;
 
    // STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
    root->height = 1 + max(height(root->left),
                           height(root->right));
 
    // STEP 3: GET THE BALANCE FACTOR OF
    // THIS NODE (to check whether this
    // node became unbalanced)
    int balance = getBalance(root);
 
    // If this node becomes unbalanced,
    // then there are 4 cases
 
    // Left Left Case
    if (balance > 1 &&
        getBalance(root->left) >= 0)
        return rightRotate(root);
 
    // Left Right Case
    if (balance > 1 &&
        getBalance(root->left) < 0)
    {
        root->left = leftRotate(root->left);
        return rightRotate(root);
    }
 
    // Right Right Case
    if (balance < -1 &&
        getBalance(root->right) <= 0)
        return leftRotate(root);
 
    // Right Left Case
    if (balance < -1 &&
        getBalance(root->right) > 0)
    {
        root->right = rightRotate(root->right);
        return leftRotate(root);
    }
 
    return root;
}
 
// A utility function to print preorder
// traversal of the tree.
// The function also prints height
// of every node
void preOrder(Node *root)
{
    if(root != NULL)
    {
        cout << root->key << " ";
        preOrder(root->left);
        preOrder(root->right);
    }
}
 
// Driver Code
int main()
{
Node *root = NULL;
 
    /* Constructing tree given in
    the above figure */
    root = insert(root, 9);
    root = insert(root, 5);
    root = insert(root, 10);
    root = insert(root, 0);
    root = insert(root, 6);
    root = insert(root, 11);
    root = insert(root, -1);
    root = insert(root, 1);
    root = insert(root, 2);
 
    /* The constructed AVL Tree would be
            9
        / \
        1 10
        / \ \
    0 5 11
    / / \
    -1 2 6
    */
 
    cout << "Preorder traversal of the "
            "constructed AVL tree is \n";
    preOrder(root);
 
    root = deleteNode(root, 10);
 
    /* The AVL Tree after deletion of 10
            1
        / \
        0 9
        / / \
    -1 5     11
        / \
        2 6
    */
 
    cout << "\nPreorder traversal after"
         << " deletion of 10 \n";
    preOrder(root);
 
    return 0;
}
 
// This code is contributed by rathbhupendra

C




// C program to delete a node from AVL Tree
#include<stdio.h>
#include<stdlib.h>
 
// An AVL tree node
struct Node
{
    int key;
    struct Node *left;
    struct Node *right;
    int height;
};
 
// A utility function to get maximum of two integers
int max(int a, int b);
 
// A utility function to get height of the tree
int height(struct Node *N)
{
    if (N == NULL)
        return 0;
    return N->height;
}
 
// A utility function to get maximum of two integers
int max(int a, int b)
{
    return (a > b)? a : b;
}
 
/* Helper function that allocates a new node with the given key and
    NULL left and right pointers. */
struct Node* newNode(int key)
{
    struct Node* node = (struct Node*)
                        malloc(sizeof(struct Node));
    node->key   = key;
    node->left   = NULL;
    node->right  = NULL;
    node->height = 1;  // new node is initially added at leaf
    return(node);
}
 
// A utility function to right rotate subtree rooted with y
// See the diagram given above.
struct Node *rightRotate(struct Node *y)
{
    struct Node *x = y->left;
    struct Node *T2 = x->right;
 
    // Perform rotation
    x->right = y;
    y->left = T2;
 
    // Update heights
    y->height = max(height(y->left), height(y->right))+1;
    x->height = max(height(x->left), height(x->right))+1;
 
    // Return new root
    return x;
}
 
// A utility function to left rotate subtree rooted with x
// See the diagram given above.
struct Node *leftRotate(struct Node *x)
{
    struct Node *y = x->right;
    struct Node *T2 = y->left;
 
    // Perform rotation
    y->left = x;
    x->right = T2;
 
    //  Update heights
    x->height = max(height(x->left), height(x->right))+1;
    y->height = max(height(y->left), height(y->right))+1;
 
    // Return new root
    return y;
}
 
// Get Balance factor of node N
int getBalance(struct Node *N)
{
    if (N == NULL)
        return 0;
    return height(N->left) - height(N->right);
}
 
struct Node* insert(struct Node* node, int key)
{
    /* 1.  Perform the normal BST rotation */
    if (node == NULL)
        return(newNode(key));
 
    if (key < node->key)
        node->left  = insert(node->left, key);
    else if (key > node->key)
        node->right = insert(node->right, key);
    else // Equal keys not allowed
        return node;
 
    /* 2. Update height of this ancestor node */
    node->height = 1 + max(height(node->left),
                           height(node->right));
 
    /* 3. Get the balance factor of this ancestor
          node to check whether this node became
          unbalanced */
    int balance = getBalance(node);
 
    // If this node becomes unbalanced, then there are 4 cases
 
    // Left Left Case
    if (balance > 1 && key < node->left->key)
        return rightRotate(node);
 
    // Right Right Case
    if (balance < -1 && key > node->right->key)
        return leftRotate(node);
 
    // Left Right Case
    if (balance > 1 && key > node->left->key)
    {
        node->left =  leftRotate(node->left);
        return rightRotate(node);
    }
 
    // Right Left Case
    if (balance < -1 && key < node->right->key)
    {
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }
 
    /* return the (unchanged) node pointer */
    return node;
}
 
/* Given a non-empty binary search tree, return the
   node with minimum key value found in that tree.
   Note that the entire tree does not need to be
   searched. */
struct Node * minValueNode(struct Node* node)
{
    struct Node* current = node;
 
    /* loop down to find the leftmost leaf */
    while (current->left != NULL)
        current = current->left;
 
    return current;
}
 
// Recursive function to delete a node with given key
// from subtree with given root. It returns root of
// the modified subtree.
struct Node* deleteNode(struct Node* root, int key)
{
    // STEP 1: PERFORM STANDARD BST DELETE
 
    if (root == NULL)
        return root;
 
    // If the key to be deleted is smaller than the
    // root's key, then it lies in left subtree
    if ( key < root->key )
        root->left = deleteNode(root->left, key);
 
    // If the key to be deleted is greater than the
    // root's key, then it lies in right subtree
    else if( key > root->key )
        root->right = deleteNode(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) || (root->right == NULL) )
        {
            struct Node *temp = root->left ? root->left :
                                             root->right;
 
            // No child case
            if (temp == NULL)
            {
                temp = root;
                root = NULL;
            }
            else // One child case
             *root = *temp; // Copy the contents of
                            // the non-empty child
            free(temp);
        }
        else
        {
            // node with two children: Get the inorder
            // successor (smallest in the right subtree)
            struct Node* temp = minValueNode(root->right);
 
            // Copy the inorder successor's data to this node
            root->key = temp->key;
 
            // Delete the inorder successor
            root->right = deleteNode(root->right, temp->key);
        }
    }
 
    // If the tree had only one node then return
    if (root == NULL)
      return root;
 
    // STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
    root->height = 1 + max(height(root->left),
                           height(root->right));
 
    // STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to
    // check whether this node became unbalanced)
    int balance = getBalance(root);
 
    // If this node becomes unbalanced, then there are 4 cases
 
    // Left Left Case
    if (balance > 1 && getBalance(root->left) >= 0)
        return rightRotate(root);
 
    // Left Right Case
    if (balance > 1 && getBalance(root->left) < 0)
    {
        root->left =  leftRotate(root->left);
        return rightRotate(root);
    }
 
    // Right Right Case
    if (balance < -1 && getBalance(root->right) <= 0)
        return leftRotate(root);
 
    // Right Left Case
    if (balance < -1 && getBalance(root->right) > 0)
    {
        root->right = rightRotate(root->right);
        return leftRotate(root);
    }
 
    return root;
}
 
// A utility function to print preorder traversal of
// the tree.
// The function also prints height of every node
void preOrder(struct Node *root)
{
    if(root != NULL)
    {
        printf("%d ", root->key);
        preOrder(root->left);
        preOrder(root->right);
    }
}
 
/* Driver program to test above function*/
int main()
{
  struct Node *root = NULL;
 
  /* Constructing tree given in the above figure */
    root = insert(root, 9);
    root = insert(root, 5);
    root = insert(root, 10);
    root = insert(root, 0);
    root = insert(root, 6);
    root = insert(root, 11);
    root = insert(root, -1);
    root = insert(root, 1);
    root = insert(root, 2);
 
    /* The constructed AVL Tree would be
            9
           /  \
          1    10
        /  \     \
       0    5     11
      /    /  \
     -1   2    6
    */
 
    printf("Preorder traversal of the constructed AVL "
           "tree is \n");
    preOrder(root);
 
    root = deleteNode(root, 10);
 
    /* The AVL Tree after deletion of 10
            1
           /  \
          0    9
        /     /  \
       -1    5     11
           /  \
          2    6
    */
 
    printf("\nPreorder traversal after deletion of 10 \n");
    preOrder(root);
 
    return 0;
}

Java




// Java program for deletion in AVL Tree
 
class Node
{
    int key, height;
    Node left, right;
 
    Node(int d)
    {
        key = d;
        height = 1;
    }
}
 
class AVLTree
{
    Node root;
 
    // A utility function to get height of the tree
    int height(Node N)
    {
        if (N == null)
            return 0;
        return N.height;
    }
 
    // A utility function to get maximum of two integers
    int max(int a, int b)
    {
        return (a > b) ? a : b;
    }
 
    // A utility function to right rotate subtree rooted with y
    // See the diagram given above.
    Node rightRotate(Node y)
    {
        Node x = y.left;
        Node T2 = x.right;
 
        // Perform rotation
        x.right = y;
        y.left = T2;
 
        // Update heights
        y.height = max(height(y.left), height(y.right)) + 1;
        x.height = max(height(x.left), height(x.right)) + 1;
 
        // Return new root
        return x;
    }
 
    // A utility function to left rotate subtree rooted with x
    // See the diagram given above.
    Node leftRotate(Node x)
    {
        Node y = x.right;
        Node T2 = y.left;
 
        // Perform rotation
        y.left = x;
        x.right = T2;
 
        // Update heights
        x.height = max(height(x.left), height(x.right)) + 1;
        y.height = max(height(y.left), height(y.right)) + 1;
 
        // Return new root
        return y;
    }
 
    // Get Balance factor of node N
    int getBalance(Node N)
    {
        if (N == null)
            return 0;
        return height(N.left) - height(N.right);
    }
 
    Node insert(Node node, int key)
    {
        /* 1. Perform the normal BST rotation */
        if (node == null)
            return (new Node(key));
 
        if (key < node.key)
            node.left = insert(node.left, key);
        else if (key > node.key)
            node.right = insert(node.right, key);
        else // Equal keys not allowed
            return node;
 
        /* 2. Update height of this ancestor node */
        node.height = 1 + max(height(node.left),
                            height(node.right));
 
        /* 3. Get the balance factor of this ancestor
        node to check whether this node became
        Wunbalanced */
        int balance = getBalance(node);
 
        // If this node becomes unbalanced, then
        // there are 4 cases Left Left Case
        if (balance > 1 && key < node.left.key)
            return rightRotate(node);
 
        // Right Right Case
        if (balance < -1 && key > node.right.key)
            return leftRotate(node);
 
        // Left Right Case
        if (balance > 1 && key > node.left.key)
        {
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }
 
        // Right Left Case
        if (balance < -1 && key < node.right.key)
        {
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }
 
        /* return the (unchanged) node pointer */
        return node;
    }
 
    /* Given a non-empty binary search tree, return the
    node with minimum key value found in that tree.
    Note that the entire tree does not need to be
    searched. */
    Node minValueNode(Node node)
    {
        Node current = node;
 
        /* loop down to find the leftmost leaf */
        while (current.left != null)
        current = current.left;
 
        return current;
    }
 
    Node deleteNode(Node root, int key)
    {
        // STEP 1: PERFORM STANDARD BST DELETE
        if (root == null)
            return root;
 
        // If the key to be deleted is smaller than
        // the root's key, then it lies in left subtree
        if (key < root.key)
            root.left = deleteNode(root.left, key);
 
        // If the key to be deleted is greater than the
        // root's key, then it lies in right subtree
        else if (key > root.key)
            root.right = deleteNode(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) || (root.right == null))
            {
                Node temp = null;
                if (temp == root.left)
                    temp = root.right;
                else
                    temp = root.left;
 
                // No child case
                if (temp == null)
                {
                    temp = root;
                    root = null;
                }
                else // One child case
                    root = temp; // Copy the contents of
                                // the non-empty child
            }
            else
            {
 
                // node with two children: Get the inorder
                // successor (smallest in the right subtree)
                Node temp = minValueNode(root.right);
 
                // Copy the inorder successor's data to this node
                root.key = temp.key;
 
                // Delete the inorder successor
                root.right = deleteNode(root.right, temp.key);
            }
        }
 
        // If the tree had only one node then return
        if (root == null)
            return root;
 
        // STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
        root.height = max(height(root.left), height(root.right)) + 1;
 
        // STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to check whether
        // this node became unbalanced)
        int balance = getBalance(root);
 
        // If this node becomes unbalanced, then there are 4 cases
        // Left Left Case
        if (balance > 1 && getBalance(root.left) >= 0)
            return rightRotate(root);
 
        // Left Right Case
        if (balance > 1 && getBalance(root.left) < 0)
        {
            root.left = leftRotate(root.left);
            return rightRotate(root);
        }
 
        // Right Right Case
        if (balance < -1 && getBalance(root.right) <= 0)
            return leftRotate(root);
 
        // Right Left Case
        if (balance < -1 && getBalance(root.right) > 0)
        {
            root.right = rightRotate(root.right);
            return leftRotate(root);
        }
 
        return root;
    }
 
    // A utility function to print preorder traversal of
    // the tree. The function also prints height of every
    // node
    void preOrder(Node node)
    {
        if (node != null)
        {
            System.out.print(node.key + " ");
            preOrder(node.left);
            preOrder(node.right);
        }
    }
 
    public static void main(String[] args)
    {
        AVLTree tree = new AVLTree();
 
        /* Constructing tree given in the above figure */
        tree.root = tree.insert(tree.root, 9);
        tree.root = tree.insert(tree.root, 5);
        tree.root = tree.insert(tree.root, 10);
        tree.root = tree.insert(tree.root, 0);
        tree.root = tree.insert(tree.root, 6);
        tree.root = tree.insert(tree.root, 11);
        tree.root = tree.insert(tree.root, -1);
        tree.root = tree.insert(tree.root, 1);
        tree.root = tree.insert(tree.root, 2);
 
        /* The constructed AVL Tree would be
        9
        / \
        1 10
        / \ \
        0 5 11
        / / \
        -1 2 6
        */
        System.out.println("Preorder traversal of "+
                            "constructed tree is : ");
        tree.preOrder(tree.root);
 
        tree.root = tree.deleteNode(tree.root, 10);
 
        /* The AVL Tree after deletion of 10
        1
        / \
        0 9
        /     / \
        -1 5 11
        / \
        2 6
        */
        System.out.println("");
        System.out.println("Preorder traversal after "+
                        "deletion of 10 :");
        tree.preOrder(tree.root);
    }
}
 
// This code has been contributed by Mayank Jaiswal

Python3




# Python code to delete a node in AVL tree
# Generic tree node class
class TreeNode(object):
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None
        self.height = 1
 
# AVL tree class which supports insertion,
# deletion operations
class AVL_Tree(object):
 
    def insert(self, root, key):
         
        # Step 1 - Perform normal BST
        if not root:
            return TreeNode(key)
        elif key < root.val:
            root.left = self.insert(root.left, key)
        else:
            root.right = self.insert(root.right, key)
 
        # Step 2 - Update the height of the
        # ancestor node
        root.height = 1 + max(self.getHeight(root.left),
                          self.getHeight(root.right))
 
        # Step 3 - Get the balance factor
        balance = self.getBalance(root)
 
        # Step 4 - If the node is unbalanced,
        # then try out the 4 cases
        # Case 1 - Left Left
        if balance > 1 and key < root.left.val:
            return self.rightRotate(root)
 
        # Case 2 - Right Right
        if balance < -1 and key > root.right.val:
            return self.leftRotate(root)
 
        # Case 3 - Left Right
        if balance > 1 and key > root.left.val:
            root.left = self.leftRotate(root.left)
            return self.rightRotate(root)
 
        # Case 4 - Right Left
        if balance < -1 and key < root.right.val:
            root.right = self.rightRotate(root.right)
            return self.leftRotate(root)
 
        return root
 
    # Recursive function to delete a node with
    # given key from subtree with given root.
    # It returns root of the modified subtree.
    def delete(self, root, key):
 
        # Step 1 - Perform standard BST delete
        if not root:
            return root
 
        elif key < root.val:
            root.left = self.delete(root.left, key)
 
        elif key > root.val:
            root.right = self.delete(root.right, key)
 
        else:
            if root.left is None:
                temp = root.right
                root = None
                return temp
 
            elif root.right is None:
                temp = root.left
                root = None
                return temp
 
            temp = self.getMinValueNode(root.right)
            root.val = temp.val
            root.right = self.delete(root.right,
                                      temp.val)
 
        # If the tree has only one node,
        # simply return it
        if root is None:
            return root
 
        # Step 2 - Update the height of the
        # ancestor node
        root.height = 1 + max(self.getHeight(root.left),
                            self.getHeight(root.right))
 
        # Step 3 - Get the balance factor
        balance = self.getBalance(root)
 
        # Step 4 - If the node is unbalanced,
        # then try out the 4 cases
        # Case 1 - Left Left
        if balance > 1 and self.getBalance(root.left) >= 0:
            return self.rightRotate(root)
 
        # Case 2 - Right Right
        if balance < -1 and self.getBalance(root.right) <= 0:
            return self.leftRotate(root)
 
        # Case 3 - Left Right
        if balance > 1 and self.getBalance(root.left) < 0:
            root.left = self.leftRotate(root.left)
            return self.rightRotate(root)
 
        # Case 4 - Right Left
        if balance < -1 and self.getBalance(root.right) > 0:
            root.right = self.rightRotate(root.right)
            return self.leftRotate(root)
 
        return root
 
    def leftRotate(self, z):
 
        y = z.right
        T2 = y.left
 
        # Perform rotation
        y.left = z
        z.right = T2
 
        # Update heights
        z.height = 1 + max(self.getHeight(z.left),
                         self.getHeight(z.right))
        y.height = 1 + max(self.getHeight(y.left),
                         self.getHeight(y.right))
 
        # Return the new root
        return y
 
    def rightRotate(self, z):
 
        y = z.left
        T3 = y.right
 
        # Perform rotation
        y.right = z
        z.left = T3
 
        # Update heights
        z.height = 1 + max(self.getHeight(z.left),
                          self.getHeight(z.right))
        y.height = 1 + max(self.getHeight(y.left),
                          self.getHeight(y.right))
 
        # Return the new root
        return y
 
    def getHeight(self, root):
        if not root:
            return 0
 
        return root.height
 
    def getBalance(self, root):
        if not root:
            return 0
 
        return self.getHeight(root.left) - self.getHeight(root.right)
 
    def getMinValueNode(self, root):
        if root is None or root.left is None:
            return root
 
        return self.getMinValueNode(root.left)
 
    def preOrder(self, root):
 
        if not root:
            return
 
        print("{0} ".format(root.val), end="")
        self.preOrder(root.left)
        self.preOrder(root.right)
 
 
myTree = AVL_Tree()
root = None
nums = [9, 5, 10, 0, 6, 11, -1, 1, 2]
 
for num in nums:
    root = myTree.insert(root, num)
 
# Preorder Traversal
print("Preorder Traversal after insertion -")
myTree.preOrder(root)
print()
 
# Delete
key = 10
root = myTree.delete(root, key)
 
# Preorder Traversal
print("Preorder Traversal after deletion -")
myTree.preOrder(root)
print()
 
# This code is contributed by Ajitesh Pathak

C#




// C# program for deletion in AVL Tree
using System;
 
public class Node
{
    public int key, height;
    public Node left, right;
 
    public Node(int d)
    {
        key = d;
        height = 1;
    }
}
 
public class AVLTree
{
    Node root;
 
    // A utility function to get height of the tree
    int height(Node N)
    {
        if (N == null)
            return 0;
        return N.height;
    }
 
    // A utility function to
    // get maximum of two integers
    int max(int a, int b)
    {
        return (a > b) ? a : b;
    }
 
    // A utility function to right
    // rotate subtree rooted with y
    // See the diagram given above.
    Node rightRotate(Node y)
    {
        Node x = y.left;
        Node T2 = x.right;
 
        // Perform rotation
        x.right = y;
        y.left = T2;
 
        // Update heights
        y.height = max(height(y.left), height(y.right)) + 1;
        x.height = max(height(x.left), height(x.right)) + 1;
 
        // Return new root
        return x;
    }
 
    // A utility function to left
    // rotate subtree rooted with x
    // See the diagram given above.
    Node leftRotate(Node x)
    {
        Node y = x.right;
        Node T2 = y.left;
 
        // Perform rotation
        y.left = x;
        x.right = T2;
 
        // Update heights
        x.height = max(height(x.left), height(x.right)) + 1;
        y.height = max(height(y.left), height(y.right)) + 1;
 
        // Return new root
        return y;
    }
 
    // Get Balance factor of node N
    int getBalance(Node N)
    {
        if (N == null)
            return 0;
        return height(N.left) - height(N.right);
    }
 
    Node insert(Node node, int key)
    {
        /* 1. Perform the normal BST rotation */
        if (node == null)
            return (new Node(key));
 
        if (key < node.key)
            node.left = insert(node.left, key);
        else if (key > node.key)
            node.right = insert(node.right, key);
        else // Equal keys not allowed
            return node;
 
        /* 2. Update height of this ancestor node */
        node.height = 1 + max(height(node.left),
                            height(node.right));
 
        /* 3. Get the balance factor of this ancestor
        node to check whether this node became
        Wunbalanced */
        int balance = getBalance(node);
 
        // If this node becomes unbalanced, then
        // there are 4 cases Left Left Case
        if (balance > 1 && key < node.left.key)
            return rightRotate(node);
 
        // Right Right Case
        if (balance < -1 && key > node.right.key)
            return leftRotate(node);
 
        // Left Right Case
        if (balance > 1 && key > node.left.key)
        {
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }
 
        // Right Left Case
        if (balance < -1 && key < node.right.key)
        {
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }
 
        /* return the (unchanged) node pointer */
        return node;
    }
 
    /* Given a non-empty binary search tree, return the
    node with minimum key value found in that tree.
    Note that the entire tree does not need to be
    searched. */
    Node minValueNode(Node node)
    {
        Node current = node;
 
        /* loop down to find the leftmost leaf */
        while (current.left != null)
        current = current.left;
 
        return current;
    }
 
    Node deleteNode(Node root, int key)
    {
        // STEP 1: PERFORM STANDARD BST DELETE
        if (root == null)
            return root;
 
        // If the key to be deleted is smaller than
        // the root's key, then it lies in left subtree
        if (key < root.key)
            root.left = deleteNode(root.left, key);
 
        // If the key to be deleted is greater than the
        // root's key, then it lies in right subtree
        else if (key > root.key)
            root.right = deleteNode(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) || (root.right == null))
            {
                Node temp = null;
                if (temp == root.left)
                    temp = root.right;
                else
                    temp = root.left;
 
                // No child case
                if (temp == null)
                {
                    temp = root;
                    root = null;
                }
                else // One child case
                    root = temp; // Copy the contents of
                                // the non-empty child
            }
            else
            {
 
                // node with two children: Get the inorder
                // successor (smallest in the right subtree)
                Node temp = minValueNode(root.right);
 
                // Copy the inorder successor's data to this node
                root.key = temp.key;
 
                // Delete the inorder successor
                root.right = deleteNode(root.right, temp.key);
            }
        }
 
        // If the tree had only one node then return
        if (root == null)
            return root;
 
        // STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
        root.height = max(height(root.left),
                    height(root.right)) + 1;
 
        // STEP 3: GET THE BALANCE FACTOR
        // OF THIS NODE (to check whether
        // this node became unbalanced)
        int balance = getBalance(root);
 
        // If this node becomes unbalanced,
        // then there are 4 cases
        // Left Left Case
        if (balance > 1 && getBalance(root.left) >= 0)
            return rightRotate(root);
 
        // Left Right Case
        if (balance > 1 && getBalance(root.left) < 0)
        {
            root.left = leftRotate(root.left);
            return rightRotate(root);
        }
 
        // Right Right Case
        if (balance < -1 && getBalance(root.right) <= 0)
            return leftRotate(root);
 
        // Right Left Case
        if (balance < -1 && getBalance(root.right) > 0)
        {
            root.right = rightRotate(root.right);
            return leftRotate(root);
        }
 
        return root;
    }
 
    // A utility function to print preorder traversal of
    // the tree. The function also prints height of every
    // node
    void preOrder(Node node)
    {
        if (node != null)
        {
            Console.Write(node.key + " ");
            preOrder(node.left);
            preOrder(node.right);
        }
    }
 
    // Driver code
    public static void Main()
    {
        AVLTree tree = new AVLTree();
 
        /* Constructing tree given in the above figure */
        tree.root = tree.insert(tree.root, 9);
        tree.root = tree.insert(tree.root, 5);
        tree.root = tree.insert(tree.root, 10);
        tree.root = tree.insert(tree.root, 0);
        tree.root = tree.insert(tree.root, 6);
        tree.root = tree.insert(tree.root, 11);
        tree.root = tree.insert(tree.root, -1);
        tree.root = tree.insert(tree.root, 1);
        tree.root = tree.insert(tree.root, 2);
 
        /* The constructed AVL Tree would be
        9
        / \
        1 10
        / \ \
        0 5 11
        / / \
        -1 2 6
        */
        Console.WriteLine("Preorder traversal of "+
                            "constructed tree is : ");
        tree.preOrder(tree.root);
 
        tree.root = tree.deleteNode(tree.root, 10);
 
        /* The AVL Tree after deletion of 10
        1
        / \
        0 9
        /     / \
        -1 5 11
        / \
        2 6
        */
        Console.WriteLine("");
        Console.WriteLine("Preorder traversal after "+
                        "deletion of 10 :");
        tree.preOrder(tree.root);
    }
}
 
/* This code contributed by PrinciRaj1992 */

Javascript




<script>
     
    // JavaScript program for deletion in AVL Tree
     
    class Node
    {
        constructor(d) {
           this.left = null;
           this.right = null;
           this.key = d;
           this.height = 1;
        }
    }
     
    let root;
   
    // A utility function to get height of the tree
    function height(N)
    {
        if (N == null)
            return 0;
        return N.height;
    }
   
    // A utility function to get maximum of two integers
    function max(a, b)
    {
        return (a > b) ? a : b;
    }
   
    // A utility function to right rotate subtree rooted with y
    // See the diagram given above.
    function rightRotate(y)
    {
        let x = y.left;
        let T2 = x.right;
   
        // Perform rotation
        x.right = y;
        y.left = T2;
   
        // Update heights
        y.height = max(height(y.left), height(y.right)) + 1;
        x.height = max(height(x.left), height(x.right)) + 1;
   
        // Return new root
        return x;
    }
   
    // A utility function to left rotate subtree rooted with x
    // See the diagram given above.
    function leftRotate(x)
    {
        let y = x.right;
        let T2 = y.left;
   
        // Perform rotation
        y.left = x;
        x.right = T2;
   
        // Update heights
        x.height = max(height(x.left), height(x.right)) + 1;
        y.height = max(height(y.left), height(y.right)) + 1;
   
        // Return new root
        return y;
    }
   
    // Get Balance factor of node N
    function getBalance(N)
    {
        if (N == null)
            return 0;
        return height(N.left) - height(N.right);
    }
   
    function insert(node, key)
    {
        /* 1. Perform the normal BST rotation */
        if (node == null)
            return (new Node(key));
   
        if (key < node.key)
            node.left = insert(node.left, key);
        else if (key > node.key)
            node.right = insert(node.right, key);
        else // Equal keys not allowed
            return node;
   
        /* 2. Update height of this ancestor node */
        node.height = 1 + max(height(node.left),
                            height(node.right));
   
        /* 3. Get the balance factor of this ancestor
        node to check whether this node became
        Wunbalanced */
        let balance = getBalance(node);
   
        // If this node becomes unbalanced, then
        // there are 4 cases Left Left Case
        if (balance > 1 && key < node.left.key)
            return rightRotate(node);
   
        // Right Right Case
        if (balance < -1 && key > node.right.key)
            return leftRotate(node);
   
        // Left Right Case
        if (balance > 1 && key > node.left.key)
        {
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }
   
        // Right Left Case
        if (balance < -1 && key < node.right.key)
        {
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }
   
        /* return the (unchanged) node pointer */
        return node;
    }
   
    /* Given a non-empty binary search tree, return the
    node with minimum key value found in that tree.
    Note that the entire tree does not need to be
    searched. */
    function minValueNode(node)
    {
        let current = node;
   
        /* loop down to find the leftmost leaf */
        while (current.left != null)
            current = current.left;
   
        return current;
    }
   
    function deleteNode(root, key)
    {
        // STEP 1: PERFORM STANDARD BST DELETE
        if (root == null)
            return root;
   
        // If the key to be deleted is smaller than
        // the root's key, then it lies in left subtree
        if (key < root.key)
            root.left = deleteNode(root.left, key);
   
        // If the key to be deleted is greater than the
        // root's key, then it lies in right subtree
        else if (key > root.key)
            root.right = deleteNode(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) || (root.right == null))
            {
                let temp = null;
                if (temp == root.left)
                    temp = root.right;
                else
                    temp = root.left;
   
                // No child case
                if (temp == null)
                {
                    temp = root;
                    root = null;
                }
                else // One child case
                    root = temp; // Copy the contents of
                                // the non-empty child
            }
            else
            {
   
                // node with two children: Get the inorder
                // successor (smallest in the right subtree)
                let temp = minValueNode(root.right);
   
                // Copy the inorder successor's data to this node
                root.key = temp.key;
   
                // Delete the inorder successor
                root.right = deleteNode(root.right, temp.key);
            }
        }
   
        // If the tree had only one node then return
        if (root == null)
            return root;
   
        // STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
        root.height = max(height(root.left), height(root.right)) + 1;
   
        // STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to check whether
        // this node became unbalanced)
        let balance = getBalance(root);
   
        // If this node becomes unbalanced, then there are 4 cases
        // Left Left Case
        if (balance > 1 && getBalance(root.left) >= 0)
            return rightRotate(root);
   
        // Left Right Case
        if (balance > 1 && getBalance(root.left) < 0)
        {
            root.left = leftRotate(root.left);
            return rightRotate(root);
        }
   
        // Right Right Case
        if (balance < -1 && getBalance(root.right) <= 0)
            return leftRotate(root);
   
        // Right Left Case
        if (balance < -1 && getBalance(root.right) > 0)
        {
            root.right = rightRotate(root.right);
            return leftRotate(root);
        }
   
        return root;
    }
   
    // A utility function to print preorder traversal of
    // the tree. The function also prints height of every
    // node
    function preOrder(node)
    {
        if (node != null)
        {
            document.write(node.key + " ");
            preOrder(node.left);
            preOrder(node.right);
        }
    }
     
    /* Constructing tree given in the above figure */
    root = insert(root, 9);
    root = insert(root, 5);
    root = insert(root, 10);
    root = insert(root, 0);
    root = insert(root, 6);
    root = insert(root, 11);
    root = insert(root, -1);
    root = insert(root, 1);
    root = insert(root, 2);
 
    /* The constructed AVL Tree would be
          9
          / \
          1 10
          / \ \
          0 5 11
          / / \
          -1 2 6
          */
    document.write(
    "Preorder traversal of the constructed AVL tree is : " +
    "</br>");
    preOrder(root);
 
    root = deleteNode(root, 10);
 
    /* The AVL Tree after deletion of 10
          1
          / \
          0 9
          /     / \
          -1 5 11
          / \
          2 6
          */
    document.write("</br>");
    document.write("Preorder traversal after "+
                       "deletion of 10 :" + "</br>");
    preOrder(root);
   
</script>

Output:  

Preorder traversal of the constructed AVL tree is 
9 1 0 -1 5 2 6 10 11 
Preorder traversal after deletion of 10 
1 0 -1 9 5 2 6 11 

Time Complexity: The rotation operations (left and right rotate) take constant time as only few pointers are being changed there. Updating the height and getting the balance factor also take constant time. So the time complexity of AVL delete remains same as BST delete which is O(h) where h is height of the tree. Since AVL tree is balanced, the height is O(Logn). So time complexity of AVL delete is O(Log n). 
Auxiliary Space: O(1), since no extra space is used.

Advantages Of AVL Trees

Summary of AVL Trees



Previous
Next
------

Introduction of B-Tree

The limitations of traditional binary search trees can be frustrating. Meet the B-Tree, the multi-talented data structure that can handle massive amounts of data with ease. When it comes to storing and searching large amounts of data, traditional binary search trees can become impractical due to their poor performance and high memory usage. B-Trees, also known as B-Tree or Balanced Tree, are a type of self-balancing tree that was specifically designed to overcome these limitations.

Unlike traditional binary search trees, B-Trees are characterized by the large number of keys that they can store in a single node, which is why they are also known as “large key” trees. Each node in a B-Tree can contain multiple keys, which allows the tree to have a larger branching factor and thus a shallower height. This shallow height leads to less disk I/O, which results in faster search and insertion operations. B-Trees are particularly well suited for storage systems that have slow, bulky data access such as hard drives, flash memory, and CD-ROMs.

B-Trees maintains balance by ensuring that each node has a minimum number of keys, so the tree is always balanced. This balance guarantees that the time complexity for operations such as insertion, deletion, and searching is always O(log n), regardless of the initial shape of the tree.

Time Complexity of B-Tree: 
 

Sr. No.AlgorithmTime Complexity
1.SearchO(log n)
2.InsertO(log n)
3.DeleteO(log n)


Note: “n” is the total number of elements in the B-tree

Properties of B-Tree: 


Following is an example of a B-Tree of minimum order 5 
Note: that in practical B-Trees, the value of the minimum order is much more than 5. 
 


We can see in the above diagram that all the leaf nodes are at the same level and all non-leafs have no empty sub-tree and have keys one less than the number of their children.

Interesting Facts about B-Trees: 

Traversal in B-Tree: 

Traversal is also similar to Inorder traversal of Binary Tree. We start from the leftmost child, recursively print the leftmost child, then repeat the same process for the remaining children and keys. In the end, recursively print the rightmost child. 

Search Operation in B-Tree: 

Search is similar to the search in Binary Search Tree. Let the key to be searched is k. 

Searching a B-Tree is similar to searching a binary tree. The algorithm is similar and goes with recursion. At each level, the search is optimized as if the key value is not present in the range of the parent then the key is present in another branch. As these values limit the search they are also known as limiting values or separation values. If we reach a leaf node and don’t find the desired key then it will display NULL.

Algorithm for Searching an Element in a B-Tree:-

C++

struct Node {
    int n;
    int key[MAX_KEYS];
    Node* child[MAX_CHILDREN];
    bool leaf;
};
 
Node* BtreeSearch(Node* x, int k) {
    int i = 0;
    while (i < x->n && k > x->key[i]) {
        i++;
    }
    if (i < x->n && k == x->key[i]) {
        return x;
    }
    if (x->leaf) {
        return nullptr;
    }
    return BtreeSearch(x->child[i], k);
}

C

BtreeSearch(x, k)
    i = 1
     
    // n[x] means number of keys in x node
    while i ? n[x] and k ? keyi[x]
        do i = i + 1
    if i  n[x] and k = keyi[x]
        then return (x, i)  
    if leaf [x]
        then return NIL
    else
        return BtreeSearch(ci[x], k)

Java

class Node {
    int n;
    int[] key = new int[MAX_KEYS];
    Node[] child = new Node[MAX_CHILDREN];
    boolean leaf;
}
 
Node BtreeSearch(Node x, int k) {
    int i = 0;
    while (i < x.n && k >= x.key[i]) {
        i++;
    }
    if (i < x.n && k == x.key[i]) {
        return x;
    }
    if (x.leaf) {
        return null;
    }
    return BtreeSearch(x.child[i], k);
}

Python3

class Node:
    def __init__(self):
        self.n = 0
        self.key = [0] * MAX_KEYS
        self.child = [None] * MAX_CHILDREN
        self.leaf = True
 
def BtreeSearch(x, k):
    i = 0
    while i < x.n and k >= x.key[i]:
        i += 1
    if i < x.n and k == x.key[i]:
        return x
    if x.leaf:
        return None
    return BtreeSearch(x.child[i], k)

C#

class Node {
    public int n;
    public int[] key = new int[MAX_KEYS];
    public Node[] child = new Node[MAX_CHILDREN];
    public bool leaf;
}
 
Node BtreeSearch(Node x, int k) {
    int i = 0;
    while (i < x.n && k >= x.key[i]) {
        i++;
    }
    if (i < x.n && k == x.key[i]) {
        return x;
    }
    if (x.leaf) {
        return null;
    }
    return BtreeSearch(x.child[i], k);
}

Javascript

// Define a Node class with properties n, key, child, and leaf
class Node {
    constructor() {
        this.n = 0;
        this.key = new Array(MAX_KEYS);
        this.child = new Array(MAX_CHILDREN);
        this.leaf = false;
    }
}
 
// Define a function BtreeSearch that takes in a Node object x and an integer k
function BtreeSearch(x, k) {
    let i = 0;
    while (i < x.n && k >= x.key[i]) {
        i++;
    }
    if (i < x.n && k == x.key[i]) {
        return x;
    }
    if (x.leaf) {
        return null;
    }
    return BtreeSearch(x.child[i], k);
}

Examples: 

Input: Search 120 in the given B-Tree. 
 


 
Solution: 
 


 


 

In this example, we can see that our search was reduced by just limiting the chances where the key containing the value could be present. Similarly if within the above example we’ve to look for 180, then the control will stop at step 2 because the program will find that the key 180 is present within the current node. And similarly, if it’s to seek out 90 then as 90 < 100 so it’ll go to the left subtree automatically, and therefore the control flow will go similarly as shown within the above example.

Below is the implementation of the above approach:

C++

// C++ implementation of search() and traverse() methods
#include <iostream>
using namespace std;
 
// A BTree node
class BTreeNode {
    int* keys; // An array of keys
    int t; // Minimum degree (defines the range for number
           // of keys)
    BTreeNode** C; // An array of child pointers
    int n; // Current number of keys
    bool leaf; // Is true when node is leaf. Otherwise false
public:
    BTreeNode(int _t, bool _leaf); // Constructor
 
    // A function to traverse all nodes in a subtree rooted
    // with this node
    void traverse();
 
    // A function to search a key in the subtree rooted with
    // this node.
    BTreeNode*
    search(int k); // returns NULL if k is not present.
 
    // Make the BTree friend of this so that we can access
    // private members of this class in BTree functions
    friend class BTree;
};
 
// A BTree
class BTree {
    BTreeNode* root; // Pointer to root node
    int t; // Minimum degree
public:
    // Constructor (Initializes tree as empty)
    BTree(int _t)
    {
        root = NULL;
        t = _t;
    }
 
    // function to traverse the tree
    void traverse()
    {
        if (root != NULL)
            root->traverse();
    }
 
    // function to search a key in this tree
    BTreeNode* search(int k)
    {
        return (root == NULL) ? NULL : root->search(k);
    }
};
 
// Constructor for BTreeNode class
BTreeNode::BTreeNode(int _t, bool _leaf)
{
    // Copy the given minimum degree and leaf property
    t = _t;
    leaf = _leaf;
 
    // Allocate memory for maximum number of possible keys
    // and child pointers
    keys = new int[2 * t - 1];
    C = new BTreeNode*[2 * t];
 
    // Initialize the number of keys as 0
    n = 0;
}
 
// Function to traverse all nodes in a subtree rooted with
// this node
void BTreeNode::traverse()
{
    // There are n keys and n+1 children, traverse through n
    // keys and first n children
    int i;
    for (i = 0; i < n; i++) {
        // If this is not leaf, then before printing key[i],
        // traverse the subtree rooted with child C[i].
        if (leaf == false)
            C[i]->traverse();
        cout << " " << keys[i];
    }
 
    // Print the subtree rooted with last child
    if (leaf == false)
        C[i]->traverse();
}
 
// Function to search key k in subtree rooted with this node
BTreeNode* BTreeNode::search(int k)
{
    // Find the first key greater than or equal to k
    int i = 0;
    while (i < n && k > keys[i])
        i++;
 
    // If the found key is equal to k, return this node
    if (keys[i] == k)
        return this;
 
    // If the key is not found here and this is a leaf node
    if (leaf == true)
        return NULL;
 
    // Go to the appropriate child
    return C[i]->search(k);
}

Java

// Java program to illustrate the sum of two numbers
 
// A BTree
class Btree {
    public BTreeNode root; // Pointer to root node
    public int t; // Minimum degree
 
    // Constructor (Initializes tree as empty)
    Btree(int t)
    {
        this.root = null;
        this.t = t;
    }
 
    // function to traverse the tree
    public void traverse()
    {
        if (this.root != null)
            this.root.traverse();
        System.out.println();
    }
 
    // function to search a key in this tree
    public BTreeNode search(int k)
    {
        if (this.root == null)
            return null;
        else
            return this.root.search(k);
    }
}
 
// A BTree node
class BTreeNode {
    int[] keys; // An array of keys
    int t; // Minimum degree (defines the range for number
           // of keys)
    BTreeNode[] C; // An array of child pointers
    int n; // Current number of keys
    boolean
        leaf; // Is true when node is leaf. Otherwise false
 
    // Constructor
    BTreeNode(int t, boolean leaf)
    {
        this.t = t;
        this.leaf = leaf;
        this.keys = new int[2 * t - 1];
        this.C = new BTreeNode[2 * t];
        this.n = 0;
    }
 
    // A function to traverse all nodes in a subtree rooted
    // with this node
    public void traverse()
    {
 
        // There are n keys and n+1 children, traverse
        // through n keys and first n children
        int i = 0;
        for (i = 0; i < this.n; i++) {
 
            // If this is not leaf, then before printing
            // key[i], traverse the subtree rooted with
            // child C[i].
            if (this.leaf == false) {
                C[i].traverse();
            }
            System.out.print(keys[i] + " ");
        }
 
        // Print the subtree rooted with last child
        if (leaf == false)
            C[i].traverse();
    }
 
    // A function to search a key in the subtree rooted with
    // this node.
    BTreeNode search(int k)
    { // returns NULL if k is not present.
 
        // Find the first key greater than or equal to k
        int i = 0;
        while (i < n && k > keys[i])
            i++;
 
        // If the found key is equal to k, return this node
        if (keys[i] == k)
            return this;
 
        // If the key is not found here and this is a leaf
        // node
        if (leaf == true)
            return null;
 
        // Go to the appropriate child
        return C[i].search(k);
    }
}

Python3

# Create a node
class BTreeNode:
  def __init__(self, leaf=False):
    self.leaf = leaf
    self.keys = []
    self.child = []
 
 
# Tree
class BTree:
  def __init__(self, t):
    self.root = BTreeNode(True)
    self.t = t
 
    # Insert node
  def insert(self, k):
    root = self.root
    if len(root.keys) == (2 * self.t) - 1:
      temp = BTreeNode()
      self.root = temp
      temp.child.insert(0, root)
      self.split_child(temp, 0)
      self.insert_non_full(temp, k)
    else:
      self.insert_non_full(root, k)
 
    # Insert nonfull
  def insert_non_full(self, x, k):
    i = len(x.keys) - 1
    if x.leaf:
      x.keys.append((None, None))
      while i >= 0 and k[0] < x.keys[i][0]:
        x.keys[i + 1] = x.keys[i]
        i -= 1
      x.keys[i + 1] = k
    else:
      while i >= 0 and k[0] < x.keys[i][0]:
        i -= 1
      i += 1
      if len(x.child[i].keys) == (2 * self.t) - 1:
        self.split_child(x, i)
        if k[0] > x.keys[i][0]:
          i += 1
      self.insert_non_full(x.child[i], k)
 
    # Split the child
  def split_child(self, x, i):
    t = self.t
    y = x.child[i]
    z = BTreeNode(y.leaf)
    x.child.insert(i + 1, z)
    x.keys.insert(i, y.keys[t - 1])
    z.keys = y.keys[t: (2 * t) - 1]
    y.keys = y.keys[0: t - 1]
    if not y.leaf:
      z.child = y.child[t: 2 * t]
      y.child = y.child[0: t - 1]
 
  # Print the tree
  def print_tree(self, x, l=0):
    print("Level ", l, " ", len(x.keys), end=":")
    for i in x.keys:
      print(i, end=" ")
    print()
    l += 1
    if len(x.child) > 0:
      for i in x.child:
        self.print_tree(i, l)
 
  # Search key in the tree
  def search_key(self, k, x=None):
    if x is not None:
      i = 0
      while i < len(x.keys) and k > x.keys[i][0]:
        i += 1
      if i < len(x.keys) and k == x.keys[i][0]:
        return (x, i)
      elif x.leaf:
        return None
      else:
        return self.search_key(k, x.child[i])
       
    else:
      return self.search_key(k, self.root)
 
 
def main():
  B = BTree(3)
 
  for i in range(10):
    B.insert((i, 2 * i))
 
  B.print_tree(B.root)
 
  if B.search_key(8) is not None:
    print("\nFound")
  else:
    print("\nNot Found")
 
 
if __name__ == '__main__':
  main()

C#

// C# program to illustrate the sum of two numbers
using System;
 
// A BTree
class Btree {
    public BTreeNode root; // Pointer to root node
    public int t; // Minimum degree
 
    // Constructor (Initializes tree as empty)
    Btree(int t)
    {
        this.root = null;
        this.t = t;
    }
 
    // function to traverse the tree
    public void traverse()
    {
        if (this.root != null)
            this.root.traverse();
        Console.WriteLine();
    }
 
    // function to search a key in this tree
    public BTreeNode search(int k)
    {
        if (this.root == null)
            return null;
        else
            return this.root.search(k);
    }
}
 
// A BTree node
class BTreeNode {
    int[] keys; // An array of keys
    int t; // Minimum degree (defines the range for number
           // of keys)
    BTreeNode[] C; // An array of child pointers
    int n; // Current number of keys
    bool leaf; // Is true when node is leaf. Otherwise false
 
    // Constructor
    BTreeNode(int t, bool leaf)
    {
        this.t = t;
        this.leaf = leaf;
        this.keys = new int[2 * t - 1];
        this.C = new BTreeNode[2 * t];
        this.n = 0;
    }
 
    // A function to traverse all nodes in a subtree rooted
    // with this node
    public void traverse()
    {
 
        // There are n keys and n+1 children, traverse
        // through n keys and first n children
        int i = 0;
        for (i = 0; i < this.n; i++) {
 
            // If this is not leaf, then before printing
            // key[i], traverse the subtree rooted with
            // child C[i].
            if (this.leaf == false) {
                C[i].traverse();
            }
            Console.Write(keys[i] + " ");
        }
 
        // Print the subtree rooted with last child
        if (leaf == false)
            C[i].traverse();
    }
 
    // A function to search a key in the subtree rooted with
    // this node.
    public BTreeNode search(int k)
    { // returns NULL if k is not present.
 
        // Find the first key greater than or equal to k
        int i = 0;
        while (i < n && k > keys[i])
            i++;
 
        // If the found key is equal to k, return this node
        if (keys[i] == k)
            return this;
 
        // If the key is not found here and this is a leaf
        // node
        if (leaf == true)
            return null;
 
        // Go to the appropriate child
        return C[i].search(k);
    }
}
 
// This code is contributed by Rajput-Ji

Javascript

// Javascript program to illustrate the sum of two numbers
 
// A BTree
class Btree
{
 
    // Constructor (Initializes tree as empty)
    constructor(t)
    {
        this.root = null;
        this.t = t;
    }
     
    // function to traverse the tree
    traverse()
    {
        if (this.root != null)
            this.root.traverse();
        document.write("<br>");
    }
     
    // function to search a key in this tree
    search(k)
    {
        if (this.root == null)
            return null;
        else
            return this.root.search(k);
    }
     
}
 
// A BTree node
class BTreeNode
{
     // Constructor
    constructor(t,leaf)
    {
        this.t = t;
        this.leaf = leaf;
        this.keys = new Array(2 * t - 1);
        this.C = new Array(2 * t);
        this.n = 0;
    }
    // A function to traverse all nodes in a subtree rooted with this node
    traverse()
    {
        // There are n keys and n+1 children, traverse through n keys
        // and first n children
        let i = 0;
        for (i = 0; i < this.n; i++) {
  
            // If this is not leaf, then before printing key[i],
            // traverse the subtree rooted with child C[i].
            if (this.leaf == false) {
                C[i].traverse();
            }
            document.write(keys[i] + " ");
        }
  
        // Print the subtree rooted with last child
        if (leaf == false)
            C[i].traverse();
    }
     
    // A function to search a key in the subtree rooted with this node.
    search(k)    // returns NULL if k is not present.
    {
     
        // Find the first key greater than or equal to k
        let i = 0;
        while (i < n && k > keys[i])
            i++;
  
        // If the found key is equal to k, return this node
        if (keys[i] == k)
            return this;
  
        // If the key is not found here and this is a leaf node
        if (leaf == true)
            return null;
  
        // Go to the appropriate child
        return C[i].search(k);
    }
}
 
// This code is contributed by patel2127


Note: The above code doesn’t contain the driver program. We will be covering the complete program in our next post on B-Tree Insertion.

There are two conventions to define a B-Tree, one is to define by minimum degree, second is to define by order. We have followed the minimum degree convention and will be following the same in coming posts on B-Tree. The variable names used in the above program are also kept the same

Applications of B-Trees:

Advantages of B-Trees:

Disadvantages of B-Trees:

Insertion and Deletion:
B-Tree Insertion 
B-Tree Deletion



Next
------