99 lines
3.0 KiB
C
99 lines
3.0 KiB
C
#ifndef INCLUDED_C_MERGESORTBU_H
|
|||
|
|
#define INCLUDED_C_MERGESORTBU_H
|
||
|
|
|
||
|
|
#ifndef INCLUDED_C_BASE_H
|
||
|
|
#include <c_Base.h>
|
||
|
|
#endif /*INCLUDED_C_BASE_H*/
|
||
|
|
|
||
|
|
|
||
|
|
#ifndef INCLUDED_C_MEMORY_H
|
||
|
|
#include <c_Memory.h>
|
||
|
|
#endif /*INCLUDED_C_MEMORY_H*/
|
||
|
|
|
||
|
|
|
||
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||
|
|
/* */
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Internal merging routine for iterative blocks.
|
||
|
|
* Re-used from the top-down logic to guarantee stability.
|
||
|
|
*/
|
||
|
|
C_STATIC_FORCE_INLINE
|
||
|
|
void c_MergeInternalBU(char* arr, c_size_t left, c_size_t mid, c_size_t right,
|
||
|
|
c_size_t size, char* aux,
|
||
|
|
int (*compar)(const void*, const void*)) {
|
||
|
|
c_size_t i = left;
|
||
|
|
c_size_t j = mid + 1;
|
||
|
|
c_size_t k = left;
|
||
|
|
|
||
|
|
// Snapshot target segment into tracking auxiliary zone
|
||
|
|
memcpy(aux + (left * size), arr + (left * size), (right - left + 1) * size);
|
||
|
|
|
||
|
|
// Merge operational slots back sequentially
|
||
|
|
while (i <= mid && j <= right) {
|
||
|
|
if (compar(aux + (i * size), aux + (j * size)) <= 0) {
|
||
|
|
memcpy(arr + (k * size), aux + (i * size), size);
|
||
|
|
i++;
|
||
|
|
} else {
|
||
|
|
memcpy(arr + (k * size), aux + (j * size), size);
|
||
|
|
j++;
|
||
|
|
}
|
||
|
|
k++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Flush remaining items sitting on the left slice
|
||
|
|
while (i <= mid) {
|
||
|
|
memcpy(arr + (k * size), aux + (i * size), size);
|
||
|
|
i++;
|
||
|
|
k++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Top-Level Iterative Framework Entry Point for Bottom-Up Merge Sort.
|
||
|
|
* Time Complexity: O(n log n) | Space Complexity: O(n) | Stable: Yes | Call Stack: O(1)
|
||
|
|
*/
|
||
|
|
C_STATIC_FORCE_INLINE
|
||
|
|
void c_MergeSortBottomUp(void* base, c_size_t num, c_size_t size,
|
||
|
|
int (*compar)(const void*, const void*)) {
|
||
|
|
if (base == NULL || num < 2 || size == 0) return;
|
||
|
|
|
||
|
|
char* arr = (char*)base;
|
||
|
|
c_size_t total_bytes = num * size;
|
||
|
|
|
||
|
|
// Optimization: Fallback to stack buffer allocation if memory payload fits locally
|
||
|
|
#define MERGE_BU_STACK_LIMIT 512
|
||
|
|
char stack_buf[MERGE_BU_STACK_LIMIT];
|
||
|
|
char* aux = NULL;
|
||
|
|
|
||
|
|
if (total_bytes <= MERGE_BU_STACK_LIMIT) {
|
||
|
|
aux = stack_buf;
|
||
|
|
} else {
|
||
|
|
aux = (char*)C_ALLOC(total_bytes);
|
||
|
|
if (aux == NULL) return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Step-wise sub-array size doubling loop: 1, 2, 4, 8, 16...
|
||
|
|
for (c_size_t width = 1; width < num; width *= 2) {
|
||
|
|
// Iterate through segments by blocks of 2 * width
|
||
|
|
for (c_size_t left = 0; left < num - width; left += 2 * width) {
|
||
|
|
c_size_t mid = left + width - 1;
|
||
|
|
c_size_t right = C_MIN(left + (2 * width) - 1, num - 1);
|
||
|
|
|
||
|
|
// Optimization: Skip merge phase if the adjacent sub-segments are already sequentially sorted
|
||
|
|
if (compar(arr + (mid * size), arr + ((mid + 1) * size)) > 0) {
|
||
|
|
c_MergeInternalBU(arr, left, mid, right, size, aux, compar);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (total_bytes > MERGE_BU_STACK_LIMIT) {
|
||
|
|
C_FREE(aux);
|
||
|
|
}
|
||
|
|
#undef MERGE_BU_STACK_LIMIT
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
#endif /*INCLUDED_C_MERGESORTBU_H*/
|