2 * Generic reusable binary-heap maintenance code.
4 * This file is copyright 2005 Simon Tatham.
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 int coverage
; /* bit flags for various if clauses */
35 #define COVERAGE(x) ( coverage |= (1 << (x)) )
37 #define COVERAGE(x) ( (void)0 )
44 bheap_cmpfn_t compare
;
50 * Our array is zero-based. Therefore the children of 0 are 1 and
51 * 2; the children of 1 are 3 and 4; of 2 are 5 and 6, and so on.
52 * In other words, the children of node n are 2n+1 and 2n+2, and
53 * the parent of node n is floor((n-1)/2).
55 #define PARENT(n) ( ((n)-1)/2 )
56 #define LCHILD(n) ( 2*(n)+1 )
57 #define RCHILD(n) ( 2*(n)+2 )
60 * This macro calls the compare function, and returns TRUE if the
61 * two elements are the wrong way up and should be swapped.
63 * It doesn't _have_ to be called on a parent and child, but its
64 * return value assumes that. So you could call it on any two
65 * elements x,y and it would return TRUE if y ought to be the
68 #define MISORDERED(bh,parent,child) \
70 (bh)->compare((bh)->compare_ctx, \
71 (bh)->elts + (parent) * (bh)->eltsize, \
72 (bh)->elts + (child) * (bh)->eltsize) > 0 )
75 * This macro swaps two elements of the heap.
77 #define SWAP(bh,x,y) do { \
78 memcpy((bh)->elts + (bh)->maxelts * (bh)->eltsize, \
79 (bh)->elts + (x) * (bh)->eltsize, (bh)->eltsize); \
80 memcpy((bh)->elts + (x) * (bh)->eltsize, \
81 (bh)->elts + (y) * (bh)->eltsize, (bh)->eltsize); \
82 memcpy((bh)->elts + (y) * (bh)->eltsize, \
83 (bh)->elts + (bh)->maxelts * (bh)->eltsize, (bh)->eltsize); \
86 bheap
*bheap_new(int maxelts
, int eltsize
, int direction
,
87 bheap_cmpfn_t compare
, void *compare_ctx
)
89 bheap
*bh
= malloc(sizeof(bheap
));
94 * Allocate one extra element of space, to use for swapping
97 bh
->elts
= malloc((maxelts
+ 1) * eltsize
);
102 bh
->maxelts
= maxelts
;
103 bh
->eltsize
= eltsize
;
104 bh
->direction
= direction
;
105 bh
->compare
= compare
;
106 bh
->compare_ctx
= compare_ctx
;
111 void *bheap_add(bheap
*bh
, void *elt
)
115 if (bh
->nelts
>= bh
->maxelts
) {
122 * Add the element to the end of the array.
124 memcpy(bh
->elts
+ bh
->nelts
* bh
->eltsize
, elt
, bh
->eltsize
);
128 * Now swap it with its parent repeatedly to preserve the heap
141 if (MISORDERED(bh
, p
, i
)) {
147 break; /* we're done */
154 void *bheap_topmost(bheap
*bh
, void *elt
)
156 if (bh
->nelts
<= 0) {
162 memcpy(elt
, bh
->elts
, bh
->eltsize
);
166 void *bheap_remove(bheap
*bh
, void *elt
)
168 if (bh
->nelts
<= 0) {
174 memcpy(elt
, bh
->elts
, bh
->eltsize
);
183 * Move the highest-index element of the heap into the top
186 SWAP(bh
, bh
->nelts
, 0);
189 * Now repeatedly move it down the heap by swapping it with
190 * the more suitable of its children.
201 if (lc
>= bh
->nelts
) {
203 break; /* we've hit bottom */
206 if (rc
>= bh
->nelts
) {
208 * Special case: there is only one child to check.
211 if (MISORDERED(bh
, i
, lc
)) {
217 /* _Now_ we've hit bottom. */
222 * The common case: there are two children and we
223 * must check them both.
225 if (MISORDERED(bh
, i
, lc
) || MISORDERED(bh
, i
, rc
)) {
228 * Pick the more appropriate child to swap with
229 * (i.e. the one which would want to be the
230 * parent if one were above the other - as one
233 if (MISORDERED(bh
, lc
, rc
)) {
243 /* This element is in the right place; we're done. */
256 int bheap_count(bheap
*bh
)
261 void bheap_free(bheap
*bh
)
274 /* we _really_ need assertions enabled, for this test */
280 #define CHECK_COVERAGE(c, statement) do { \
281 coverage &= ~ (1 << (c)); \
283 assert(coverage & (1 << (c))); \
284 checked_coverage |= (1 << (c)); \
293 int intcmp(void *vctx
, const void *av
, const void *bv
)
295 const int *a
= (const int *)av
;
296 const int *b
= (const int *)bv
;
297 int *ctx
= (int *)vctx
;
299 assert(ctx
== &intcmp_ctx
);
310 int *ret
= bheap_add(bh
, &x
);
320 assert(bheap_count(bh
) == n
);
325 int out1
, *ret1
, out2
, *ret2
;
327 ret1
= bheap_topmost(bh
, &out1
);
328 ret2
= bheap_remove(bh
, &out2
);
331 assert(x
< 0); /* test the tests! */
332 assert(ret1
== NULL
);
333 assert(ret2
== NULL
);
337 assert(x
>= 0); /* test the tests! */
338 assert(ret1
== &out1
);
339 assert(ret2
== &out2
);
340 assert(out1
== out2
);
343 /* Now find x in _our_ array and remove it. */
344 for (i
= 0; i
< n
; i
++) {
345 assert(array
[i
] >= x
);
350 array
[n
-1] = array
[i
];
356 assert(i
< n
); /* we expect to have found it */
360 assert(bheap_count(bh
) == n
);
365 coverage
= checked_coverage
= 0;
367 /* Regression test - this used to report access violations when run under
369 bh
= bheap_new(2, sizeof(int), +1, intcmp
, &intcmp_ctx
);
376 bh
= bheap_new(MAX
, sizeof(int), +1, intcmp
, &intcmp_ctx
);
379 * Various sets of adds and removes which test all the code
380 * paths marked with COVERAGE() statements.
382 CHECK_COVERAGE(2, add(4));
383 CHECK_COVERAGE(3, add(7));
384 CHECK_COVERAGE(4, add(2));
385 CHECK_COVERAGE(1, add(6));
388 CHECK_COVERAGE(5, add(8));
390 CHECK_COVERAGE(0, add(9)); /* check the full-heap case */
392 CHECK_COVERAGE(7, rem(1));
393 CHECK_COVERAGE(8, rem(2));
394 CHECK_COVERAGE(9, rem(3));
395 CHECK_COVERAGE(14, rem(4));
399 CHECK_COVERAGE(19, rem(8));
400 CHECK_COVERAGE(6, rem(-1)); /* and check the empty-heap case */
401 CHECK_COVERAGE(8, rem(-1)); /* and check the empty-heap case */
406 CHECK_COVERAGE(12, rem(1));
413 CHECK_COVERAGE(13, rem(1));
421 CHECK_COVERAGE(17, rem(1));
430 CHECK_COVERAGE(16, rem(1));
442 CHECK_COVERAGE(18, rem(1));
443 CHECK_COVERAGE(15, rem(2));
445 CHECK_COVERAGE(10, rem(4));
446 CHECK_COVERAGE(11, rem(5));
451 * See what happens with compare equality.
486 * Interleave some adds and removes, turning the heap into a
487 * real priority queue rather than a glorified sorter.
489 * We add the digits of pi in order, and keep the heap size
490 * capped at 5 by extracting one before adding the next.
492 * Python code that generates this test sequence:
496 for c in "314159265358979323846264338327950288":
502 print (" rem(%d); /"+"* %s *"+"/") % (d, repr(list))
505 print (" add(%d); /"+"* %s *"+"/") % (c, repr(list))
510 print (" rem(%d); /"+"* %s *"+"/") % (d, repr(list))
517 add(4); /* [1, 3, 4] */
518 add(1); /* [1, 1, 3, 4] */
519 add(5); /* [1, 1, 3, 4, 5] */
520 rem(1); /* [1, 3, 4, 5] */
521 add(9); /* [1, 3, 4, 5, 9] */
522 rem(1); /* [3, 4, 5, 9] */
523 add(2); /* [2, 3, 4, 5, 9] */
524 rem(2); /* [3, 4, 5, 9] */
525 add(6); /* [3, 4, 5, 6, 9] */
526 rem(3); /* [4, 5, 6, 9] */
527 add(5); /* [4, 5, 5, 6, 9] */
528 rem(4); /* [5, 5, 6, 9] */
529 add(3); /* [3, 5, 5, 6, 9] */
530 rem(3); /* [5, 5, 6, 9] */
531 add(5); /* [5, 5, 5, 6, 9] */
532 rem(5); /* [5, 5, 6, 9] */
533 add(8); /* [5, 5, 6, 8, 9] */
534 rem(5); /* [5, 6, 8, 9] */
535 add(9); /* [5, 6, 8, 9, 9] */
536 rem(5); /* [6, 8, 9, 9] */
537 add(7); /* [6, 7, 8, 9, 9] */
538 rem(6); /* [7, 8, 9, 9] */
539 add(9); /* [7, 8, 9, 9, 9] */
540 rem(7); /* [8, 9, 9, 9] */
541 add(3); /* [3, 8, 9, 9, 9] */
542 rem(3); /* [8, 9, 9, 9] */
543 add(2); /* [2, 8, 9, 9, 9] */
544 rem(2); /* [8, 9, 9, 9] */
545 add(3); /* [3, 8, 9, 9, 9] */
546 rem(3); /* [8, 9, 9, 9] */
547 add(8); /* [8, 8, 9, 9, 9] */
548 rem(8); /* [8, 9, 9, 9] */
549 add(4); /* [4, 8, 9, 9, 9] */
550 rem(4); /* [8, 9, 9, 9] */
551 add(6); /* [6, 8, 9, 9, 9] */
552 rem(6); /* [8, 9, 9, 9] */
553 add(2); /* [2, 8, 9, 9, 9] */
554 rem(2); /* [8, 9, 9, 9] */
555 add(6); /* [6, 8, 9, 9, 9] */
556 rem(6); /* [8, 9, 9, 9] */
557 add(4); /* [4, 8, 9, 9, 9] */
558 rem(4); /* [8, 9, 9, 9] */
559 add(3); /* [3, 8, 9, 9, 9] */
560 rem(3); /* [8, 9, 9, 9] */
561 add(3); /* [3, 8, 9, 9, 9] */
562 rem(3); /* [8, 9, 9, 9] */
563 add(8); /* [8, 8, 9, 9, 9] */
564 rem(8); /* [8, 9, 9, 9] */
565 add(3); /* [3, 8, 9, 9, 9] */
566 rem(3); /* [8, 9, 9, 9] */
567 add(2); /* [2, 8, 9, 9, 9] */
568 rem(2); /* [8, 9, 9, 9] */
569 add(7); /* [7, 8, 9, 9, 9] */
570 rem(7); /* [8, 9, 9, 9] */
571 add(9); /* [8, 9, 9, 9, 9] */
572 rem(8); /* [9, 9, 9, 9] */
573 add(5); /* [5, 9, 9, 9, 9] */
574 rem(5); /* [9, 9, 9, 9] */
575 add(0); /* [0, 9, 9, 9, 9] */
576 rem(0); /* [9, 9, 9, 9] */
577 add(2); /* [2, 9, 9, 9, 9] */
578 rem(2); /* [9, 9, 9, 9] */
579 add(8); /* [8, 9, 9, 9, 9] */
580 rem(8); /* [9, 9, 9, 9] */
581 add(8); /* [8, 9, 9, 9, 9] */
582 rem(8); /* [9, 9, 9, 9] */
583 rem(9); /* [9, 9, 9] */
594 for (i
= 0; i
< 20; i
++) {
595 if (!(coverage
& (1 << i
)))
596 printf("coverage is missing %d\n", i
);
597 else if (!(checked_coverage
& (1 << i
)))
598 printf("checked_coverage is missing %d\n", i
);
602 printf("finished testing, no assertions failed\n");