Skip to content

Commit 443558d

Browse files
committed
Implement stable_partition.
1 parent d88104c commit 443558d

File tree

2 files changed

+92
-17
lines changed

2 files changed

+92
-17
lines changed

array_alg.h

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -441,11 +441,36 @@ ALGDEF T *NS(partition)(
441441
void *predicate_ctx
442442
);
443443

444-
ALGDEF T *NS(partition_copy)(
444+
/// Partition a range by copying the elements that satisfy a predicate into one buffer,
445+
/// and the ones that fail to another.
446+
/// Note that this function is stable.
447+
ALGDEF void NS(partition_copy)(
445448
const T *first,
446449
const T *last,
447-
T *restrict out_false,
448-
T *restrict out_true,
450+
T **out_true,
451+
T **out_false,
452+
int (*predicate)(const T*, void*),
453+
void *predicate_ctx
454+
);
455+
456+
/// Calls malloc.
457+
ALGDEF T *NS(stable_partition)(
458+
T *first,
459+
T *last,
460+
int (*predicate)(const T*, void*),
461+
void *predicate_ctx
462+
);
463+
464+
/// Like above, but does not call `malloc`.
465+
/// You must provide a buffer.
466+
/// requires:
467+
/// - sizeof(buffer) >= the number of false entries in the range [first, last)
468+
// Note that sizeof(buffer) >= last - first will be sufficient.
469+
470+
ALGDEF T *NS(stable_partition_with_buffer)(
471+
T *first,
472+
T *last,
473+
T *buffer,
449474
int (*predicate)(const T*, void*),
450475
void *predicate_ctx
451476
);
@@ -644,17 +669,16 @@ ALGDEF void NS(insertion_sort_stable)(
644669

645670
/// Sort an array in a stable way with a merge sort variety.
646671
/// By stable, we mean that the order of equivalent elements is preserved.
647-
/// Note this function allocates memory with malloc.
648-
672+
/// Calls malloc.
649673
ALGDEF void NS(stable_sort)(
650674
T* first,
651675
T* last,
652676
int (*compare)(const T*, const T*, void*),
653677
void* compare_ctx
654678
);
655679

656-
/// Like above, but does not call `malloc`.
657-
/// You provide a buffer.`
680+
/// Like above, but does not call malloc.
681+
/// You must provide a buffer.
658682
/// requires:
659683
/// - sizeof(buffer) >= (last - first) / 2
660684
ALGDEF void NS(stable_sort_with_buffer)(
@@ -766,6 +790,7 @@ ALGDEF T *NS(_merge_sort_adaptive_with_buffer_n)(
766790
void* compare_ctx
767791
);
768792

793+
769794
#ifdef ARRAY_ALG_IMPLEMENTATION
770795

771796
ALGDEF T *NS(find_if)(
@@ -1515,11 +1540,41 @@ ALGDEF T *NS(partition)(
15151540
return out;
15161541
}
15171542

1518-
ALGDEF T *NS(partition_copy)(
1543+
ALGDEF T *NS(stable_partition_with_buffer)(
1544+
T *first,
1545+
T *last,
1546+
T *buffer,
1547+
int (*predicate)(const T*, void*),
1548+
void *predicate_ctx
1549+
)
1550+
{
1551+
T *out_false = buffer;
1552+
T *out_true = first;
1553+
NS(partition_copy)(first, last, &out_true, &out_false, predicate, predicate_ctx);
1554+
memcpy(out_true, buffer, sizeof(T) * (out_false - buffer));
1555+
return out_true;
1556+
}
1557+
1558+
ALGDEF T *NS(stable_partition)(
1559+
T *first,
1560+
T *last,
1561+
int (*predicate)(const T*, void*),
1562+
void *predicate_ctx
1563+
)
1564+
{
1565+
// TODO: this is not the best implementation
1566+
if (first == last) return last;
1567+
T *buffer = malloc((last - first) * sizeof(T));
1568+
T *point = NS(stable_partition_with_buffer)(first, last, buffer, predicate, predicate_ctx);
1569+
free(buffer);
1570+
return point;
1571+
}
1572+
1573+
ALGDEF void NS(partition_copy)(
15191574
const T *first,
15201575
const T *last,
1521-
T *restrict out_false,
1522-
T *restrict out_true,
1576+
T **out_true,
1577+
T **out_false,
15231578
int (*predicate)(const T*, void*),
15241579
void *predicate_ctx
15251580
) {
@@ -1528,19 +1583,19 @@ ALGDEF T *NS(partition_copy)(
15281583
{
15291584
if (predicate(first, predicate_ctx))
15301585
{
1531-
*out_true = *first;
1532-
++out_true;
1586+
*(*out_true) = *first;
1587+
++(*out_true);
15331588
}
15341589
else
15351590
{
1536-
*out_false = *first;
1537-
++out_false;
1591+
*(*out_false) = *first;
1592+
++(*out_false);
15381593
}
15391594
++first;
15401595
}
1541-
return out_false;
15421596
}
15431597

1598+
15441599
ALGDEF T *NS(partition_point_n)(
15451600
const T *first,
15461601
size_t n,

test/tests.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,15 @@ void test_partition(void) {
390390
int numbers[] = { 1, 2, 3, 4, 5, 6};
391391
int odd[3];
392392
int even[3];
393-
int* false_end = intv_partition_copy(numbers, numbers + 6, odd, even, pred_is_even, NULL);
394393

395-
assert(false_end - odd == 3);
394+
395+
int *out_odd = odd;
396+
int *out_even = even;
397+
398+
intv_partition_copy(numbers, numbers + 6, &out_even, &out_odd, pred_is_even, NULL);
399+
400+
assert(out_odd - odd == 3);
401+
assert(out_even - even == 3);
396402

397403
for (int i = 0; i < 3; ++i) {
398404
assert(odd[i] % 2 == 1);
@@ -401,6 +407,19 @@ void test_partition(void) {
401407
}
402408
}
403409

410+
void test_stable_partition(void) {
411+
int numbers[] = { 1, 2, 3, 4, 5, 6};
412+
int *point = intv_stable_partition(numbers, numbers + 6, pred_is_even, NULL);
413+
414+
assert(point - numbers == 3);
415+
416+
int expected[] = { 2, 4, 6, 1, 3, 5 };
417+
418+
for (int i = 0; i < ARRAY_LEN(numbers); ++i) {
419+
assert(numbers[i] == expected[i]);
420+
}
421+
}
422+
404423
void test_is_sorted(void) {
405424
{
406425
int numbers[] = { 1, 2, 3, 4, 5, 6};
@@ -840,6 +859,7 @@ int main() {
840859
printf("-- test_minmax --\n"); test_minmax();
841860
printf("-- test_minmax_element --\n"); test_minmax_element();
842861
printf("-- test_partition --\n"); test_partition();
862+
printf("-- test_stable_partition --\n"); test_stable_partition();
843863
printf("-- test_is_sorted --\n"); test_is_sorted();
844864
printf("-- test_binary_search --\n"); test_binary_search();
845865
printf("-- test_permutation --\n"); test_permutation();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy