/*This is a Java Program to implement Binary Heap. A binary heap is a heap data structure created using a binary tree. It can be seen as a binary tree with two additional constraints:
i) The shape property: the tree is a complete binary tree; that is, all levels of the tree, except possibly the last one (deepest) are fully filled and if the last level of the tree is not complete, the nodes of that level are filled from left to right.
ii) The heap property: each node is greater than or equal to each of its children according to a comparison predicate defined for the data structure.
Here binary heap is implemented using arrays.*/

/**
 *  Java Program to Implement Binary Heap
 */

import java.util.Scanner;
import java.util.Arrays;
import java.util.NoSuchElementException;

/** Class BinaryHeap **/
class BinaryHeap
{
    /** The number of children each node has **/
    private static final int d = 2;
    private int heapSize;
    private int[] heap;

    /** Constructor **/
    public BinaryHeap(int capacity)
    {
        heapSize = 0;
        heap = new int[capacity + 1];
        Arrays.fill(heap, -1);
    }

    /** Function to check if heap is empty **/
    public boolean isEmpty( )
    {
        return heapSize == 0;
    }

    /** Check if heap is full **/
    public boolean isFull( )
    {
        return heapSize == heap.length;
    }

    /** Clear heap */
    public void makeEmpty( )
    {
        heapSize = 0;
    }

    /** Function to  get index parent of i **/
    private int parent(int i)
    {
        return (i - 1)/d;
    }

    /** Function to get index of k th child of i **/
    private int kthChild(int i, int k)
    {
        return d * i + k;
    }

    /** Function to insert element */
    public void insert(int x)
    {
        if (isFull( ) )
            throw new NoSuchElementException("Overflow Exception");
        /** Percolate up **/
        heap[heapSize++] = x;
        heapifyUp(heapSize - 1);
    }

    /** Function to find least element **/
    public int findMin( )
    {
        if (isEmpty() )
            throw new NoSuchElementException("Underflow Exception");
        return heap[0];
    }

    /** Function to delete min element **/
    public int deleteMin()
    {
        int keyItem = heap[0];
        delete(0);
        return keyItem;
    }

    /** Function to delete element at an index **/
    public int delete(int ind)
    {
        if (isEmpty() )
            throw new NoSuchElementException("Underflow Exception");
        int keyItem = heap[ind];
        heap[ind] = heap[heapSize - 1];
        heapSize--;
        heapifyDown(ind);
        return keyItem;
    }

    /** Function heapifyUp  **/
    private void heapifyUp(int childInd)
    {
        int tmp = heap[childInd];
        while (childInd > 0 && tmp < heap[parent(childInd)])
            {
                heap[childInd] = heap[ parent(childInd) ];
                childInd = parent(childInd);
            }
        heap[childInd] = tmp;
    }

    /** Function heapifyDown **/
    private void heapifyDown(int ind)
    {
        int child;
        int tmp = heap[ ind ];
        while (kthChild(ind, 1) < heapSize)
            {
                child = minChild(ind);
                if (heap[child] < tmp)
                    heap[ind] = heap[child];
                else
                    break;
                ind = child;
            }
        heap[ind] = tmp;
    }

    /** Function to get smallest child **/
    private int minChild(int ind)
    {
        int bestChild = kthChild(ind, 1);
        int k = 2;
        int pos = kthChild(ind, k);
        while ((k <= d) && (pos < heapSize))
            {
                if (heap[pos] < heap[bestChild])
                    bestChild = pos;
                pos = kthChild(ind, k++);
            }
        return bestChild;
    }

    /** Function to print heap **/
    public void printHeap()
    {
        System.out.print("\nHeap = ");
        for (int i = 0; i < heapSize; i++)
            System.out.print(heap[i] +" ");
        System.out.println();
    }
}

/** Class BinaryHeapTest **/
public class BinaryHeapTest
{
    public static void main(String[] args)
    {
        Scanner scan = new Scanner(System.in);
        System.out.println("Binary Heap Test\n\n");
        System.out.println("Enter size of Binary heap");
        /** Make object of BinaryHeap **/
        BinaryHeap bh = new BinaryHeap(scan.nextInt() );
        char ch;
        /**  Perform Binary Heap operations  **/
        do
            {
                System.out.println("\nBinary Heap Operations\n");
                System.out.println("1. insert ");
                System.out.println("2. delete min");
                System.out.println("3. check full");
                System.out.println("4. check empty");
                System.out.println("5. clear");
                int choice = scan.nextInt();
                switch (choice)
                    {
                    case 1 :
                        try
                            {
                                System.out.println("Enter integer element to insert");
                                bh.insert( scan.nextInt() );
                            }
                        catch (Exception e)
                            {
                                System.out.println(e.getMessage() );
                            }
                        break;
                    case 2 :
                        try
                            {
                                System.out.println("Min Element : "+ bh.deleteMin());
                            }
                        catch (Exception e)
                            {
                                System.out.println(e.getMessage() );
                            }
                        break;
                    case 3 :
                        System.out.println("Full status = "+ bh.isFull());
                        break;
                    case 4 :
                        System.out.println("Empty status = "+ bh.isEmpty());
                        break;
                    case 5 :
                        bh.makeEmpty();
                        System.out.println("Heap Cleared\n");
                        break;
                    default :
                        System.out.println("Wrong Entry \n ");
                        break;
                    }
                /** Display heap **/
                bh.printHeap();
                System.out.println("\nDo you want to continue (Type y or n) \n");
                ch = scan.next().charAt(0);
            }
        while (ch == 'Y'|| ch == 'y');
    }
}

/*
Enter size of Binary heap
10

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
1
Enter integer element to insert
24

Heap = 24

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
1
Enter integer element to insert
6

Heap = 6 24

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
1
Enter integer element to insert
28

Heap = 6 24 28

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
1
Enter integer element to insert
5

Heap = 5 6 28 24

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
1
Enter integer element to insert
63

Heap = 5 6 28 24 63

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
1
Enter integer element to insert
19

Heap = 5 6 19 24 63 28

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
1
Enter integer element to insert
94

Heap = 5 6 19 24 63 28 94

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
2
Min Element : 5

Heap = 6 24 19 94 63 28

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
2
Min Element : 6

Heap = 19 24 28 94 63

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
2
Min Element : 19

Heap = 24 63 28 94

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
2
Min Element : 24

Heap = 28 63 94

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
2
Min Element : 28

Heap = 63 94

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
2
Min Element : 63

Heap = 94

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
2
Min Element : 94

Heap =

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
2
Underflow Exception

Heap =

Do you want to continue (Type y or n)

y

Binary Heap Operations

1. insert
2. delete min
3. check full
4. check empty
5. clear
4
Empty status = true

Heap =

Do you want to continue (Type y or n)

n