0

Say I'm using a std::vector as the underlying container of a std::priority_queue.

Should I consider this vector as a representation of a binary heap (Becz., a priority_queue is similar to a heap (Am I right in this assumption? An awful lot of sources on the web use these 2 terms interchangeably)? or is it just a normal vector?

By "representation of a binary heap" I mean -> 0th element of the vector is the root of the bin. heap, 1st element is the left child of the root, 2nd element is the right child & so on.

  • *"Should I consider this vector as a representation of a binary heap"* -- why not consider the vector as a representation of a `std::priority_queue` and not worry about deeper details? – JaMiT Jan 26 '23 at 06:27
  • C++ standard does not guarantee that. In a specific implementation of C++ standard library this may hold but fail once you use another implementation. If you need the elements of the vector, you can just use `std::make_heap`, `std::push_heap`, `std::pop_heap` from the beginning – erzya Jan 26 '23 at 06:32
  • Are you just curious, or planning to access the underlying data directly (which would be very fragile). – Pepijn Kramer Jan 26 '23 at 08:44
  • @PepijnKramer I want to calculate the median of a group of numbers. I thought I can push all those numbers into a priority_queue & access the element at middle (if the underlying vector is interpreted as just a vector & not complete binary tree). – PhiloRobotist Jan 26 '23 at 20:25
  • @erzya I can't use the method you suggested for my case, can I? – PhiloRobotist Jan 26 '23 at 20:30
  • it is probably easier just putting everything in a vector and using std::sort then pick the middle. Both should be around N log(N) complexity – Pepijn Kramer Jan 27 '23 at 05:50
  • @PhiloRobotist Since your goal is a heap rather than a priority queue, why don't you use a heap? Going after your goal indirectly tends to result in confusing code. – JaMiT Jan 28 '23 at 06:19

1 Answers1

1

Yes, the standard mandates that the member functions of priority_queue have the same effect as applying the relevant heap operation to the underlying container:

void push(const value_type& x);

Effects: As if by:

c.push_back(x); 
push_heap(c.begin(), c.end(), comp); 

void push(value_type&& x);

Effects: As if by:

c.push_back(std::move(x)); 
push_heap(c.begin(), c.end(), comp);

template<container-compatible-range<T> R> void push_range(R&& rg);

Effects: Insert all elements of rg in c.

Postconditions: is_­heap(c.begin(), c.end(), comp) is true.

template<class... Args> void emplace(Args&&... args);

Effects: As if by:

c.emplace_back(std::forward<Args>(args)...); 
push_heap(c.begin(), c.end(), comp); 

void pop();

Effects: As if by:

pop_heap(c.begin(), c.end(), comp); 
c.pop_back(); 

priqueue.members

Because the underlying container is a protected member, and access controls apply to naming the member, you can get at any priority_queues data, even if it isn't a base-subobject of a class you've defined.

template <typename T, typename Container, typename Comp>
const Container & get_container(const std::priority_queue<T, Container, Comp> & queue) {
    struct access_t : std::priority_queue<T, Container, Comp> {
        auto member_ptr() { return &access_t::c; }
    } access;
    auto ptr = access.member_ptr();
    return queue.*ptr;
}
Caleth
  • 52,200
  • 2
  • 44
  • 75
  • I don't understand how this answers my question. – PhiloRobotist Jan 26 '23 at 20:33
  • @PhiloRobotist the member functions of `std::priority_queue` are defined in terms of `std::push_heap`, `std::pop_heap`, and the constructors in terms of `std::make_heap`. I've edited to show one way you can observe the data in the queue. – Caleth Jan 27 '23 at 09:24