Java implements maximum (small) heap and heap sorting, TopN problems

Keywords: Java less SQL

Java implements maximum (small) heap and heap sorting, TopN problems

Articles Catalogue

Java implementation heap

What is a heap, first to understand the principle, and then to see how to achieve.

  • The definition of heap: Heap is a general term for a special data structure in computer science. A heap is usually an array object that can be considered as a complete binary tree.

The heap can be seen as a tree, and the subtree of the tree is also a heap. The largest heap is that the parent node is larger than the child node, and the root node is the largest node; the smallest heap is that the father node is smaller than the child node, and the root node is the smallest node.

We should pay attention to the difference between heap and binary lookup tree. The binary lookup tree is that the left child node is smaller than the parent node, and the right child node is larger than the parent node.

As shown in the figure, the maximum heap and the minimum heap are:

And we know that a binary tree has one property:
There is such a relationship between the subscript of the current node and the subscript of the child node: the subscript of the left child node is twice the subscript of the parent node, and the subscript of the right child node is twice the subscript of the parent node, i.e. left_son.index = current.index * 2, right_son.index = current.index * 2 + 1.

And this binary tree is a complete binary tree. Combining with the above characteristics, it is very suitable to use array to realize heap.

Let's move on to the topic of heap construction.

Reactor Construction

Given an array {1,9,7,5,18,4}, the corresponding binary tree is as follows:

We need to adjust it to the maximum heap, which is the initialization process of the heap: from top to bottom, or from bottom to top, but from top to bottom, we have to traverse the subtree every time, repeating many nodes. So the bottom-up method is adopted, that is, starting from the last child node (because it is the parent of the last node, so its subscript is size / 2), so that its two children are compared, find the large value and then compare with the value of the parent node. If the value of the parent node is small, then the child node and the parent node exchange, and then recursively compare. Then step by step, recursively, until the root node ends.

7 is the last node with child nodes, compared with the left and right son nodes, and then with the large commutator, then recursively repeat this step down to the smaller node, and then recursively repeat this step up to the root node, where 7 is the largest, no replacement, and then recursively to the upper layer, that is, 1 and 7 comparison, specific. The process is as follows:

Implementation code:

    /**
     * Constructor
     */
    public MaxHeap(int[] num, int capacity) {
        this(capacity + 1);
        if (num.length > capacity) {
            try {
                throw new Exception("capacity Not less than the length of the array!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        for (int i = 1, len = num.length; i <= len; ++i) {
            ++size;
            heap[i] = num[i - 1];
        }
        adjustment(); // Adjustment Reactor
    }

    /**
     * Adjustment Reactor
     */
    private void adjustment() {
        for (int i = size / 2; i >= 1; --i) {
            int temp = heap[i]; // The current operation of the node, from back to front, the first operation is the node with sub-nodes.
            int max_index = i * 2; // Left Son Node of Current Node
            while (max_index <= size) { // The left son node of the current node is valid, and the subscript 1 to size is valid.
                if (max_index < size && heap[max_index] < heap[max_index + 1])
                    ++max_index;
                if (temp > heap[max_index]) break;
                heap[max_index / 2] = heap[max_index];
                max_index *= 2;
            }
            heap[max_index / 2] = temp;
        }
    }

Insertion of heap

Insert the largest heap: insert the element at the end, because it is already the largest heap, so you just need to compare layer by layer. For example, I want to insert 10, only need to compare with 7, and then compare with 18.

Implementation code:

    public void insert(int element) {
        if (size == 0) { // The heap is empty, insert directly into position 0
            heap[1] = element;
            ++size;
        } else if (size >= heap.length - 1) { // Full capacity, throw exception
            try {
                throw new Exception("The capacity is full!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            int index = ++size; // index is the subscript for the newly inserted element
            while (index != 1 && element > heap[index / 2]) {
                // Keep looking up until you find a node larger than the insertion element, or at the root node
                heap[index] = heap[index / 2];
                index /= 2;
            }
            heap[index] = element;
        }
    }

Heap deletion

Delete the root node: This is simpler, move the last node directly to the root node, and then adjust the heap, which is the construction process above.

Implementation code:

    public int removeMax() {
        int max = heap[1];
        heap[1] = heap[size--];
        adjustment();
        return max;
    }

Specific implementation code

Detailed implementation code (I write a special, can only save int, can add generic class MaxHeap < T extends Comparable < T > according to their own needs, that is, the heap can store custom type elements, but to achieve the Comparable interface, and then use compareTo method to replace greater than or less sign, int to T):

package com.au.sql;

public class MaxHeap {
    private int[] heap; // array
    private int size; // Number of actual stored data
    private final static int DEFAULT_CAPACITY = 100; // Default heap capacity

    /**
     * Multiple constructors are designed to meet different needs
     */
    public MaxHeap() {
        this(DEFAULT_CAPACITY);
    }

    public MaxHeap(int capacity) {
        heap = new int[capacity + 1];
        size = 0;
    }

    public MaxHeap(int[] num) {
        this(num, num.length * 2);
    }

    public MaxHeap(int[] num, int capacity) {
        this(capacity + 1);
        if (num.length > capacity) {
            try {
                throw new Exception("capacity Not less than the length of the array!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        for (int i = 1, len = num.length; i <= len; ++i) {
            ++size;
            heap[i] = num[i - 1];
        }
        adjustment(); // Adjustment Reactor
    }

    /**
     * Adjustment Reactor
     */
    private void adjustment() {
        for (int i = size / 2; i >= 1; --i) {
            int temp = heap[i]; // The current operation of the node, from back to front, the first operation is the node with sub-nodes.
            int max_index = i * 2; // Left Son Node of Current Node
            while (max_index <= size) { // The left son node of the current node is valid, and the subscript 1 to size is valid.
                if (max_index < size && heap[max_index] < heap[max_index + 1])
                    ++max_index;
                if (temp > heap[max_index]) break;
                heap[max_index / 2] = heap[max_index];
                max_index *= 2;
            }
            heap[max_index / 2] = temp;
        }
    }

    public void insert(int element) {
        if (size == 0) { // The heap is empty, insert directly into position 0
            heap[1] = element;
            ++size;
        } else if (size >= heap.length - 1) { // Full capacity, throw exception
            try {
                throw new Exception("The capacity is full!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            int index = ++size; // index is the subscript for the newly inserted element
            while (index != 1 && element > heap[index / 2]) {
                // Keep looking up until you find a node larger than the insertion element, or at the root node
                heap[index] = heap[index / 2];
                index /= 2;
            }
            heap[index] = element;
        }
    }

    /**
     * Delete maximum
     *
     * @return
     */
    public int removeMax() {
        int max = heap[1];
        heap[1] = heap[size--];
        adjustment();
        return max;
    }

    public void print() {
        for (int i = 1; i <= size; ++i) {
            System.out.print(heap[i] + " ");
        }
    }

    public static void main(String[] args) {
        MaxHeap maxHeap = new MaxHeap();
        maxHeap.insert(12);
        maxHeap.insert(14);
        maxHeap.insert(11);
        maxHeap.insert(110);
        maxHeap.insert(411);
        maxHeap.insert(11);
        maxHeap.print();
        System.out.println();
        System.out.println("============");
        MaxHeap maxHeap1 = new MaxHeap(new int[]{12, 14, 11, 110, 411, 11});
        maxHeap1.removeMax();
        maxHeap1.print();


    }
}

Heap sorting

Understanding the principle of heap, heap sorting should be very simple, we only need to exchange the last node with the first node, replace a size minus 1, then adjust the heap, and then cycle this step until the end of the replacement.

Implementation code (using the above code):

    public void heapSort() {
        int temp = size; // Let's save the original size first.
        for (int i = size; i > 0; --i) {
            --size;
            int t = heap[i];
            heap[i] = heap[1];
            heap[1] = t;
            adjustment();
        }
        size = temp;
    }

TopN Problem

This is much simpler, just maintain an N.

    public int topN(int n) {
        int temp = size; // Let's save the original size first.
        int res = 0;
        for (int i = size; i > 0; --i) {
            if (--n == 0) {
                res = heap[1];
                break;
            }
            --size;
            int t = heap[i];
            heap[i] = heap[1];
            heap[1] = t;
            adjustment();
        }
        size = temp;
        return res;
    }

Posted by perezf on Mon, 19 Aug 2019 05:00:41 -0700