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

  • 相关阅读:
    css清除浮动
    对象遍历
    vue 小工具
    数据库优化-聚合索引
    mysql修改唯一索引
    输出带pre的调试信息
    mysql的group by优化跟limit优化
    地址联动数据抓取
    php7新特新
    linux同步系统时间
  • 原文地址:https://www.cnblogs.com/lz87/p/7006853.html
Copyright © 2011-2022 走看看