1

C++ std::priority_queue just need a partial order. But if its implementation is a binary heap, how does it works? For example: assume we have a partially ordered set ( {a, b, c, x}, {c < b, b < a, c < a} ), x has nothing to do with a, b, c. Then a max-heap is:

layer 1:    x
layer 2:  b   x
layer 3: x x a c

After a pop operation, in a way commonly seen in text books, i.e. replace the root with c and decrease the size by 1. Then we need to heapify the tree below, at the root:

layer 1:    c
layer 2:  b   x
layer 3: x x a

We will swap c and b as c < b, won't we? And what? We still don't have a valid heap since b < a. But b cannot "see" a.

jogojapan
  • 68,383
  • 11
  • 101
  • 131
updogliu
  • 6,066
  • 7
  • 37
  • 50
  • 2
    Is it mentioned somewhere that `priority_queue` works with partial ordering? – Hindol Sep 14 '12 at 07:05
  • Isn't it? I'm not sure. How about `std::sort`? I believe a self-written quick-sort can support partial order. – updogliu Sep 14 '12 at 07:11
  • While `std::sort` will surely terminate even with a partial order in almost all implementations, I very much doubt the result would be much use. The reason is that it too assumes a weak ordering, just like jogojapan described in his answer. The most reasonable thing you *can* do with a partial order is to [sort it topologically](http://en.wikipedia.org/wiki/Topological_sorting). – MvG Sep 14 '12 at 07:30
  • @MvG How can you specify a `partial ordering` in `std::sort()`? If `a is not less than b`, it automatically assumes `a is greater than or equal to b`. Thus in a sense every possible pair is comparable. – Hindol Sep 14 '12 at 07:38
  • @updogliu Yes, a ___self-written___ quick sort may support partial ordering given the comparison function returns `yes`, `no` and `not comparable`. But it introduces a lot of ambiguity in the algorithm itself. What will you do if a pair is not comparable? Whatever you do, it gets in the way of sorting the rest of the elements just like the heap example you have given. – Hindol Sep 14 '12 at 07:44
  • @MvG I think it is not the case. If we have got the transitive closure, it is more efficient to use a quick-sort to do topological sort. – updogliu Sep 14 '12 at 07:46
  • @Hindol: Take the partial ordering from the question. `std::sort` might see that `x` is incomparable to both `a` and `b` (i.e. neither is less than the other), interpret that as `x == a && x == b` and from that implicitely and incorrectly conclude `a == b`. As a result, there might be results which order `a` before `b`. – MvG Sep 14 '12 at 07:54
  • @updogliu: What do you mean by transitive closure? A partial order is transitive in the sense that if an item *is* comparable to two others, than those two are comparable to one another, in a way consistent with the first comparisons. But this transitivity for `<` doesn't imply a transitivity for the `==` implied by the interpretation from my previous comment. Therefore, quicksort may still fail to achieve the correct result. – MvG Sep 14 '12 at 07:57
  • To make my point more hands-on: assume you do a quick-sort, where at some point you have `x` as the pivot element, `a` in the left half and `b` in the right half. Since neither compares different from `x`, there is no need to swap anything. As a result, both will stay in their respective halfs, and the result will be `a x b` which isn't a topological ordering. – MvG Sep 14 '12 at 08:01
  • 1
    @MvG std::sort is ill-defined on a partial ordering because a partial ordering is not necessarily a strict weak ordering as it may invalidate the *transitivity of incomparability*: http://stackoverflow.com/questions/24286209/topological-sorting-using-stdsort – Herbert Jun 18 '14 at 14:06

1 Answers1

7

The requirement for priority_queue is (§23.6.4 of the C++ Standard) that the comparator defines a strict, weak ordering. The latter is defined in §25.4/4 as follows:

The term strict refers to the requirement of an irreflexive relation (!comp(x, x) for all x), and the term weak to requirements that are not as strong as those for a total ordering, but stronger than those for a partial ordering. If we define equiv(a, b) as !comp(a, b) && !comp(b, a), then the requirements are that comp and equiv both be transitive relations:

— comp(a, b) && comp(b, c) implies comp(a, c)

— equiv(a, b) && equiv(b, c) implies equiv(a, c) [ Note: Under these conditions, it can be shown that

i) equiv is an equivalence relation

ii) comp induces a well-defined relation on the equivalence classes determined by equiv

iii) The induced relation is a strict total ordering. — end note ]

In other words, the comparator-defined relation does not have to be total, but it must be total with respect to the equivalence classes defined by a hypothetical relation equiv, which defines all elements as equal that are not less-than or greater-than each other.

To put it in even simpler terms, any elements not covered by the comparator relation will be treated as equal.

jogojapan
  • 68,383
  • 11
  • 101
  • 131
  • I'm not sure what you mean by the highlighted sentence. The code will apply the comparison function over all elements. It's impossible to have an element not covered by the comparator relation. – James Kanze Sep 14 '12 at 07:27
  • Thanks a lot! For a long time I have been misinterpreting "strict weak order" as "strict partial order". BTW, I still think a quick-sort can handle strict partial order. – updogliu Sep 14 '12 at 07:30
  • 1
    @JamesKanze, “not covered” here means that neither `a < b` nor `b < a` is true. For a weak order, this doesn't imply `a == b`, but as far as the ordering is concerned, `a` and `b` will nevertheless be treated as equal. – MvG Sep 14 '12 at 07:32
  • @JamesKanze _An element (or rather, a pair of elements a,b) not being covered_ refers to the situation that neither `a – jogojapan Sep 14 '12 at 07:37
  • @MvG If neither `a < b` nor `b < a`, then the two objects are equivalent (and belong to the same equivalence class). In other words, they are equal (for the definition of equal used by these functions). They're still "covered" (at least under what I would understand from the word---at least two of you seem to understand something different, so I don't know). – James Kanze Sep 14 '12 at 08:04
  • @JamesKanze, the point is that a *weak* ordering on the elements corresponds to a *total* ordering on the equivalence classes. As I denoted element equality by `==` and equivalence equality by `equiv`, the distinction is *important* here, no matter whether you call the comparison `<` or `comp`. – MvG Sep 14 '12 at 08:26