11

As I understand, binary heap does not support removing random elements. What if I need to remove random elements from a binary heap?

Obviously, I can remove an element and re-arrange the entire heap in O(N). Can I do better?

Michael
  • 41,026
  • 70
  • 193
  • 341

3 Answers3

24

Yes and no.

The problem is a binary heap does not support search for an arbitrary element. Finding it is itself O(n).

However, if you have a pointer to the element (and not only its value) - you can swap the element with the rightest leaf, remove this leaf, and than re-heapify the relevant sub-heap (by sifting down the newly placed element as much as needed). This results in O(logn) removal, but requires a pointer to the actual element you are looking for.

amit
  • 175,853
  • 27
  • 231
  • 333
  • Thanks. I mean the case when I have a pointer (index) to the element. – Michael Sep 02 '12 at 06:13
  • @Michael: if you have a pointer - you can do it in `O(logn)`, with the algorithm described in this answer. – amit Sep 02 '12 at 06:14
  • Thanks. Is there any other data structure (not binary heap), which works as a priority queue and supports remove by pointer/index in O(1)? – Michael Sep 02 '12 at 06:17
  • 1
    @Michael A [Skip-List](http://en.wikipedia.org/wiki/Skip_list) can find minimum in `O(1)`, insert `O(logn)` search in `O(logn)` remove element by pointer in `O(1)` [all on average]. However - it is seldom needed to remove an element by pointer, and a search is usually first needed, and it is `O(logn)` – amit Sep 02 '12 at 06:21
  • 4
    This does not work. It is most certainly possible, that the last element of the heap when inserted into the position you are removing, needs to be filtered 'up' rather than down. http://pastebin.com/3ez6U2JF. – deltaluca Sep 26 '13 at 14:26
  • Assuming you have the key of the element you're looking for (assuming a key/value heap) you can search in average logarithmic time too. – deltaluca Sep 26 '13 at 14:56
  • @deltaluca Not in a binary heap and without additional DS. If you think I am wrong - please provide a search algorithm in a binary heap in logarithmic time or provide reference for one. – amit Sep 26 '13 at 23:36
  • @deltaluca And yes, the element needs to be "filtered up" - as I said, after the replacement - you need to re-heapify. Did you read the answer? – amit Sep 26 '13 at 23:39
  • @amit. did you? "and than re-heapify the relevant sub-heap (by sifting down the newly placed element as much as needed)" you only mention sifting down the newly placed element, not that you may well need to sift up which is more than just re-heapifying the sub-heap. – deltaluca Sep 27 '13 at 08:20
  • To the search, I didn't actually mean to post that comment, but I'll explain my thoughts anyways. If you have the key of the value, then you can do a breadth/depth first search pruning the sub-heaps the key cannot possibly be contained in. At worst, it's linear but though I can't do the analysis to work out a real average complexity, I can imagine it would be 'something' logarithmic. – deltaluca Sep 27 '13 at 08:24
  • @Michael: A linked list works as a priority queue and can do O(1) removal if you have a pointer. Drawback is that insertion is O(n). – Jim Mischel May 24 '14 at 02:44
8

Amit is right in his answer but here is one more nuance:

the position of the removed item (where you put the right-most leaf) can be required to be bubbled up (compare with parent and move up until parent is larger than you). Sometimes it is required to bubble down (compare with children and move down until all children are smaller than you). It all depends on the case.

imslavko
  • 6,596
  • 2
  • 34
  • 43
3

Depends on what is meant by "random element." If it means that the heap contains elements [e1, e2, ..., eN] and one wants to delete some ei (1 <= i <= N), then this is possible.

If you are using a binary heap implementation from some library, it might be that it doesn't provide you with the API that you need. In that case, you should look for another library that has it.

If you were to implement it yourself, you would need two additional calls:

  1. A procedure deleteAtIndex(heap, i) that deletes the node at index i by positioning the last element in the heap array at i, decrementing the element count, and finally shuffling down/up the new ith element to maintain the heap invariant. The most common use of this procedure is to "pop" the heap by calling deleteAtIndex(heap, 1) -- assuming 1-origin indexing. This operation will run O(log n) (though, to be complete, I'll note that the highest bound can be improved up to O(log(log n)) depending on some assumptions about your elements' keys).

  2. A procedure deleteElement(heap, e) that deletes the element e (your arbitrary element). Your heap algorithm would maintain an array ElementIndex such that ElementIndex[e] returns the current index of element e: calling deleteAtIndex(heap, ElementIndex[e]) will then do what you want. It will also run in O(log n) because the array access is constant.

Since binary heaps are often used in algorithms that merely pop the highest (or lowest) priority element (rather than deleting arbitrary elements), I imagine that some libraries might miss on the deleteAtIndex API to save space (the extra ElementIndex array mentioned above).

ruben
  • 71
  • 3