6

I read a few articles which said that, in a heap, only the root element can be deleted. However, why can't we delete elements, using the below approach?

  1. Find the index of the key element you want to delete
  2. Swap this element with the last element, so the key becomes the last element
  3. Re-heapify starting at the original index of the key(which you have now swapped with the last element)
  4. Reduce size of heap by 1

So, the code would look like

static void delete(int[] a, int key)
    {
        int i = 0;
        for(i = 0;i<a.length;i++)
        {
            if(a[i] == key)
                break;
        }
        swap(a, i, a.length-1);

        max_heapify_forheapsort(a, i, a.length-2);
    }

static void max_heapify_forheapsort(int[] a, int i, int limit)
    {
        int left = (2*i)+1;
        int right = (2*i) + 2;
        int next = i;

        if(left <= limit && a[left] > a[i])
            next = left;
        if(right <= limit && a[right] > a[next] )
            next = right;

        if(next!=i)
        {
            swap(a, next, i);
            max_heapify_forheapsort(a, next, limit);
        }
    }
saltandwater
  • 791
  • 2
  • 9
  • 25

3 Answers3

19

It's certainly possible to delete elements from a heap with sift-up or sift-down operations as you propose. (It's similarly possible to change the key of any item in the heap and use sift-up or -down operations to restore the heap property.)

The tricky bit is what you stated quickly at the outset: "Find the index." A naive implementation requires O(n) to do this, and that kills heap efficiency. What people mean when they say "you can't delete" is that with a naive implementation you can't delete efficiently.

Fortunately it's not hard to make finding the index O(1). Just maintain a "reverse map" in parallel with the heap array, e.g. a hash map from objects to heap array indices. It's easy to update this map without adding asymptotic complexity to any of the heap operations, and with it - as you point out - delete has complexity O(log n). The sift up/down dominates the map lookup to find the index.

If you're interested in a tested implementation, here's one where the heap contains indices into another array of objects. Therefore the reverse map is implemented as an array q->locs[k], which is the index of the heap element that contains k (which is an index into the object table).

Many problems in computer science can be solved by adding a level of indirection!

Edit

Since OP asked about why a sift up might be required to delete, consider the min heap

          1
    20          2 
 30    40    3     4

We want to delete 30, so move 4 (the last array element) into its position:

          1
    20          2 
 4     40    3 

Clearly a sift up is required.

Gene
  • 46,253
  • 4
  • 58
  • 96
  • you mention sift-up or sift-down in your answer. Won't a delete operation always be sift-down ? – saltandwater Oct 19 '16 at 03:28
  • 3
    I don't think so. The deleted element doesn't have to be an ancestor of the heap array's last, so the heap property doesn't require it. – Gene Oct 19 '16 at 03:38
  • I once said, as a joke, "Enough levels of indirection makes any problem solvable." I got a lot of flak for that one from people who thought I was being serious. – Jim Mischel Oct 19 '16 at 13:17
  • How do you know whether to sift-up or sift-down? – mic Aug 07 '20 at 18:13
  • I have coded & run some tests, both down-heap & up-heap are required, as the element deleted need not be ancestor of last element, and also because deleted element may be an internal node - which may require one of the down-heap & up-heap operations, based on the value of last node - when we do both it correctly fixes the heap property. Only required number of both operations happen, only until the heap property is fixed. – Manohar Reddy Poreddy Aug 19 '20 at 19:00
0

If it is Minheap,

  • Store the element to be removed in a variable.
  • Replace the element in with smallest integer. Heapify Up the to the root.
  • Remove the root to Heapify down to maintain the heap property.
  • Return the stored variable. Source- GeeksforGeeks.
Utkarsh
  • 137
  • 9
-2

The root of the heap has a property that is true in relation to all other elements. When the root is removed, only one other element will satisfy that condition, which will not (likely) be the one you want to remove. Swapping elements will therefore invalidate the heap with nondeterministic results.

Nosretep
  • 17
  • 2
  • Deleting in the middle of the heap does not "invalidate the heap" any more than deleting the root item does. The procedure for re-adjusting the heap after deletion is well known. – Jim Mischel Oct 19 '16 at 13:20
  • I see now that I slightly misunderstood the original question. Based on how it was asked, I thought the proposal was to swap the root with some other "random" element in the heap and then delete the root.However, instead the proposal was to swap the matching element with the last element and remove it by resizing the heap. There is no benefit to this because as is pointed out simply deleting in the middle of the heap and re-adjusting would involve less modifications to the data than this approach. – Nosretep Oct 21 '16 at 18:17
  • The method for removing an item in the middle of the heap is to replace the item to be removed with the last item in the heap, decrease the count, and then move the new item up or down the heap as required. The point is that "swap the matching element with the last element" is the first step in re-adjusting. – Jim Mischel Oct 21 '16 at 20:22