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

  • 相关阅读:
    2011年 CIO简历该怎么写?
    OC内存管理
    【Android游戏开发十五】关于Android 游戏开发中 OnTouchEvent() 触屏事件的性能优化笔记!
    【Android游戏开发十二】(保存游戏数据 [上文])详解SharedPreference 与 FIleInputStream/FileOutputStream将数据存储到SD卡中!
    ORA16014: 日志 1 的序列号 83 未归档, 没有可用的目的
    【Android游戏开发十四】深入Animation,在SurfaceView中照样使用Android—Tween Animation!
    2011来临 IT人员应该具备哪些技能?
    垃圾控件DatePicker
    【Android游戏开发十八】解放手指,利用传感器开发游戏!(本文讲解在SurfaceView中用重力传感器控制圆球的各方向移动)
    【Android游戏开发十三】(保存游戏数据 [下文])详解SQLite存储方式,并把SQLite的数据库文件存储在SD卡中!!!
  • 原文地址:https://www.cnblogs.com/lz87/p/7006853.html
Copyright © 2011-2022 走看看