zoukankan      html  css  js  c++  java
  • [LintCode] Heapify

    Given an integer array, heapify it into a min-heap array.

    For a heap array A, A[0] is the root of heap, and for each A[i], A[i * 2 + 1] is the left child of A[i] and A[i * 2 + 2] is the right child of A[i].
     
    Clarification

    What is heap? 

    • Heap is a data structure, which usually have three methods: push, pop and top. where "push" add a new element to the heap, "pop" delete the minimum/maximum element in the heap, "top" return the minimum/maximum element.
    What is heapify?
    • Convert an unordered integer array into a heap array. If it is min-heap, for each element A[i], we will get A[i * 2 + 1] >= A[i] and A[i * 2 + 2] >= A[i]. 
    What if there is a lot of solutions?
    • Return any of them.
    Example

    Given [3,2,1,4,5], return [1,2,3,4,5] or any legal heap array.

    Challenge 

    O(n) time complexity

    This problem is about implementing a ascending priority queue ADT using min binary heap.

    It should support O(log n) insertion, O(log n) delete min, O(1) get min. 

    Min Heap is a tree with the following two special properties.

    1. The key of a node must be <= the keys of its children nodes

    2. It must form a complete binary tree. 

    Heapify an array, O(n)

    Leaf nodes always satisfy the min heap property so we only need to heapify the non-leaf nodes;

    For a complete binary tree, if there are an odd number of nodes of 2 * n + 1, then there are 

    n + 1 leaf nodes and n non-leaf nodes; If there are an even number of nodes of 2 * n, then there 

    are n leaf nodes and n non-leaf nodes. So the biggest index of non-leaf nodes is array.length / 2 - 1 = n - 1. 

    Starting from the last non-leaf node, all the way back to root, we percolate down each of these nodes.

    Insert, O(log n)

    1. Increase the heap size by 1

    2. Add the new element at the end of the heap

    3. Heapify this element from bottom to top(Percolate up)

        if the new element's index is k, its parent's index is (k - 1) / 2. 

    Delete Min, O(log n)

    1. Save the root element's value 

    2. Copy the last element's value into root and delete the last element

    3. Percolate Down the new root element.

    Delete Arbitrary , O(log n) if we don't need to find the arbitrary element first; O(n) if we need to find it before deletion.

    If we delete an arbitrary element that is in the middle of the heap(neither root nor leaf nodes), this element has both 

    parent node and children nodes, so we still swap its value with the last element then delete the last element, but instead of just precolate down the last element in its new position, we need to heapify the whole heap, iterating all the non-leaf nodes.

    1. Swap value with the last element 

    2. Delete the last element

    3. Percolate Down on all non-leaf nodes

    The above arbitrary deletion algorithm takes O(n) time even if the location of the to-be deleted element is given. In fact, there is no need to percolate down on all non-leaf nodes. 

    The following algorithm takes O(logn) time.

    1. Swap the last node's value with the deletion node's value, then remove this last node. This step maintains the "complete binary tree" invariant.

    2. Fix the invariant where for each node, its key must be <= both of its children nodes' keys.

      a. If there is no parent node for the replacement node or key of replacement node >= its parent node's key:  percolate down this replacement node;

      b. else we have key of replacement node < its parent node's key: percolate up this replacement node. 

     1 public class Solution {
     2     //heapify an array
     3     public void heapify(ArrayList<Integer> A) {
     4         if(A == null || A.size() <= 1)
     5         {
     6             return;
     7         }
     8         for(int i = A.size() / 2 - 1; i >= 0; i--)
     9         {
    10             percolateDown(A, i);
    11         }
    12     }
    13     private void percolateDown(ArrayList<Integer> A, int idx)
    14     {
    15         int minIdx = idx;
    16         int leftChildIdx = 2 * idx + 1;
    17         int rightChildIdx = 2 * idx + 2;
    18         
    19         if(leftChildIdx < A.size() && A.get(leftChildIdx) < A.get(minIdx))
    20         {
    21             minIdx = leftChildIdx;
    22         }
    23         if(rightChildIdx < A.size() && A.get(rightChildIdx) < A.get(minIdx))
    24         {
    25             minIdx = rightChildIdx;
    26         }
    27         
    28         if(minIdx != idx)
    29         {
    30             int temp = A.get(idx);
    31             A.set(idx, A.get(minIdx));
    32             A.set(minIdx, temp);
    33             percolateDown(A, minIdx);
    34         }
    35     }
    36     //insert
    37     public void insert(ArrayList<Integer> A, int val)
    38     {
    39         A.add(val);
    40         //precolate up the new added element
    41         int idx = A.size() - 1;
    42         while(idx > 0 && val < A.get((idx - 1) / 2)){
    43             A.set(idx, A.get(idx - 1) / 2);
    44             idx = (idx - 1) / 2;
    45         }
    46         A.set(idx, val);
    47     }
    48     //delete min
    49     public int deleteMin(ArrayList<Integer> A)
    50     {
    51         //swap the root element with the last element in A
    52         int min = A.get(0);
    53         A.set(0, A.get(A.size() - 1));
    54         A.remove(A.size() - 1);
    55         //precolate down the new root
    56         percolateDown(A, 0);
    57         return min;
    58     }
    59     
    60     //delete arbitrary, assuming we know the idx of to be deleted element
    61     public int delete(ArrayList<Integer> A, int deleteIdx)
    62     {
    63         int del = ArrayList.get(deleteIdx);
    64         //swap the to be deleted element with the last element in A
    65         //then remove the last element
    66         A.set(deleteIdx, A.get(A.size() - 1));
    67         A.remove(A.size() - 1);
    68         
    69         //need to heapify all the non-leaf nodes as the deleted element 
    70         //has both parent and children nodes
    71         for(int i = A.size() / 2 - 1; i >= 0; i++)
    72         {
    73             percolateDown(A, i);
    74         }
    75         return del;
    76     }
    77 }

    Optimized O(logn) aribtrary deletion

     1 private void percolateUp(ArrayList<Integer> A, int idx) {
     2     if(idx < 0) {
     3         return;
     4     }
     5     int val = A.get(idx);
     6     while(idx > 0 && val < A.get((idx - 1) / 2)) {
     7         A.set(idx, A.get((idx - 1) / 2));
     8         idx = (idx - 1) / 2;
     9     }
    10     A.set(idx, val);
    11 }
    12 public int delete(ArrayList<Integer> A, int deleteIdx) {
    13     int del = ArrayList.get(deleteIdx);
    14     A.set(deleteIdx, A.get(A.size() - 1));
    15     A.remove(A.size() - 1);
    16     int parentIdx = (deleteIdx - 1) / 2;
    17     if(deleteIdx == 0 || A.get(deleteIdx) >= A.get(parentIdx)) {
    18         percolateDown(A, deleteIdx);
    19     }
    20     else {
    21         percolateUp(A, deleteIdx);
    22     }
    23     return del;
    24 }

    Related Problems

    HeapSort

  • 相关阅读:
    Hadoop命令手册
    编程算法
    综合8种子排序算法总结和比较
    android 创建一个新的每次project什么时候 请问自己主动 参加 V7依赖?
    【JDBC】java PreparedStatement操作oracle数据库
    【cocos2dx 加载资源目录】
    Project Euler:Problem 39 Integer right triangles
    矿Java开发学习之旅------&gt;Java排序算法经典的二分法插入排序
    [React Intl] Render Content with Placeholders using react-intl FormattedMessage
    [React Intl] Install and Configure the Entry Point of react-intl
  • 原文地址:https://www.cnblogs.com/lz87/p/7006853.html
Copyright © 2011-2022 走看看