#include c_err_t c_LSD_RadixSort(void* base, c_size_t num, c_size_t elem_size, c_size_t w_bytes, c_LSD_ExtractorFn extractor, void* args, c_Allocator_t* allocator) { // 边界拦截与防御性参数过滤 if (!base || elem_size == 0 || w_bytes == 0 || !extractor) { return C_ERR_PARAM; } if (num < 2) { return C_ERR_OK; // 零个或单个元素无需排序,平滑退出 } c_Allocator_t local_alloc; if (allocator) { local_alloc = *allocator; } else { local_alloc = c_DefaultAllocator; } char* array_base = (char*)base; // 前置逆向除法整数溢出防御审计:阻止开辟影子辅助缓冲区时可能触发的无符号算术回绕 if (((c_size_t)-1) / elem_size < num) { return C_ERR_NOMEM; } // 在堆上利用分配器托管开辟等大的一维扁平影子缓冲区(Auxiliary Array)用于稳定分配搬运 char* aux = (char*)c_Allocator_Alloc(&local_alloc, num * elem_size); if (!aux) { return C_ERR_NOMEM; } // 🌟【LSD 基数核心常数】:一个字节有 8 位,基数桶(R)的物理字母表总上限固定为 256 #define C_LSD_R 256 c_size_t count[C_LSD_R + 1]; // 从最低字节(d = 0)一路稳定向最高字节(d = w_bytes - 1)单调向前推进 for (c_size_t d = 0; d < w_bytes; d++) { // 步骤 1:清空本轮的计数桶 memset(count, 0, sizeof(count)); // 步骤 2:频率计数(Counting)。调用 extractor 虚函数提取对应的 8 位无符号整型键值 for (c_size_t i = 0; i < num; i++) { uint8_t bucket_key = extractor(array_base + (i * elem_size), d, args); count[bucket_key + 1]++; // 错位计数,为下一步的前缀变换蓄力 } // 步骤 3:前缀累计和转换(Prefix Sums)。将频率转化为影子缓冲区的精确起始物理下标 for (c_size_t r = 0; r < C_LSD_R; r++) { count[r + 1] += count[r]; } // 步骤 4:无伤分配搬运(Data Distribution)。将数据深拷贝转储至影子缓冲区 aux 中 // 严格遵循稳定排序原则,维持原同值键的物理相对顺序不动 for (c_size_t i = 0; i < num; i++) { uint8_t bucket_key = extractor(array_base + (i * elem_size), d, args); // 获取本元素在影子缓冲中安全分配的槽位索引,并递增计数指针位置 c_size_t dest_idx = count[bucket_key]++; // 严密检查,阻止任何因为多态提取器越界导致的非线性越界踩踏 if (dest_idx < num) { memcpy(aux + (dest_idx * elem_size), array_base + (i * elem_size), elem_size); } } // 步骤 5:回写刷新(Copy Back)。将本轮基于第 d 字节排好序的影子结果完全回写覆盖回原数组 memcpy(array_base, aux, num * elem_size); } #undef C_LSD_R // 销毁并原路回收影子缓冲,阻断任何悬空残留 c_Allocator_Free(&local_alloc, aux); return C_ERR_OK; }