Topic: Additional heap functions


Author: Marc <marc.glisse@gmail.com>
Date: Tue, 8 Sep 2009 00:54:09 CST
Raw View
Hello,

do you have any comment on the following? Suggestion, advice,
improvement, flame?
I started discussing this in clc++m, message <8aba5fa9-28c2-4451-
a6dd-8b369c969429@l35g2000pra.googlegroups.com>.

Additional heap functions

(based on n2723, since concepts are going away)

In the synopsis of [algorithms], after pop_heap, add:

template<class RandomAccessIterator>
   void remove_heap(RandomAccessIterator first, RandomAccessIterator
last,
                 RandomAccessIterator target);
template<class RandomAccessIterator, class Compare>
   void remove_heap(RandomAccessIterator first, RandomAccessIterator
last,
                 RandomAccessIterator target, Compare comp);

template<class RandomAccessIterator>
   void update_heap(RandomAccessIterator first, RandomAccessIterator
last,
                 RandomAccessIterator target);
template<class RandomAccessIterator, class Compare>
   void update_heap(RandomAccessIterator first, RandomAccessIterator
last,
                 RandomAccessIterator target, Compare comp);


In [alg.heap.operations], before [make.heap], add:

remove_heap

template<class RandomAccessIterator>
   void remove_heap(RandomAccessIterator first, RandomAccessIterator
last,
                 RandomAccessIterator target);
template<class RandomAccessIterator, class Compare>
   void remove_heap(RandomAccessIterator first, RandomAccessIterator
last,
                 RandomAccessIterator target, Compare comp);

Effects: Swaps the value in the location target with the value in the
location last - 1 and makes [first,last - 1) into a heap. The range
[first,target) is not affected.

Requires: The range [first,last) shall be a valid heap and target
shall be in
this range. The type of *first shall satisfy the Swappable
requirements (37),
the MoveConstructible requirements (Table 33), and the the
MoveAssignable
requirements (Table 35).

Complexity: At most 2 * log(last - first) comparisons.


update_heap

template<class RandomAccessIterator>
   void update_heap(RandomAccessIterator first, RandomAccessIterator
last,
                 RandomAccessIterator target);
template<class RandomAccessIterator, class Compare>
   void update_heap(RandomAccessIterator first, RandomAccessIterator
last,
                 RandomAccessIterator target, Compare comp);

Effects: Makes [first,last) into a heap. If !(*target < old) or comp
(*target,
old)==false, [target+1,last) is not affected. If !(old < *target) or
comp(old,
*target)==false, [first,target) is not affected.

Requires: target shall be in the range [first,last). For some possibly
different value "old" of *target, the range [first,last) shall be a
valid
heap. The type of *first shall satisfy the Swappable requirements
(37), the
MoveConstructible requirements (Table 33), and the the MoveAssignable
requirements (Table 35).

Complexity: At most 2 * log(last - first) comparisons.




Justification:

these 2 operations currently require a possibly linear time call to
make_heap,
whereas they can easily be made logarithmic time.

I expect the most frequent use will be:
read first
*first=new_value
update_heap(first,last,first)

which is a small but nice time improvement over:
pop_heap
read last-1
*(last-1)=new_value
push_heap(first,last)

(from 3*log(n) down to somewhere between constant and 2*log(n))

The main argument against adding these functions is that since the STL
heap is
array-based and not tree-based, operations on it invalidate pointers
to its
elements. It then looks like the pointer target was obtained by
linearly
traversing the array, so we shouldn't be so worried about getting a
good
complexity for the removal. However,
- the operations to find the pointer target may be much faster than
the
   comparisons and moves that happen when we change the structure
- it is possible to update an external pointer in the move assignment
of an
   array element.

Future:
- push_heap and update_heap could return an iterator to the new
position (I
   don't currently need it, but it could be useful, and is essentially
free)
- provide an interface for these functions in priority_queue
- it should be possible to call these functions with iterator first
and last
   and const_iterator target, but for now I am just copying std::rotate
which
   doesn't allow it.

Doubts:
- I don't know about requiring Swappable, as it is already implied by
the 2
   other requirements, I just copied it from pop_heap (for some reason
   pop and sort require it but not push or make).
- I don't know exactly how much to specify the effects of the
functions. It is
   useful to specify enough, to have some guarantees on which iterators
are not
   invalidated. On the other hand, saying it is a heap kind of defines
the
   implementation, so details may not be needed.
- the name of the functions can change (delete_heap, erase_heap,
purge_heap?
   *_from_heap?), I am not set on this one. However, overloading
pop_heap to
   handle remove_heap makes it hard to provide a version that doesn't
require
   comp.
- the only other occurence of 3 iterators on the same range I found is
   std::rotate, where arguments are in order first, middle, last.
However, here
   I think it more natural to first pass the range and then the element
to
   remove. I don't really care though.
- I don't like the name "last" for the past-the-end variable, but that
is what is used
   everywhere in the standard. Looking at the rest of the standard,
maybe target
   should be pos(ition) instead.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]