52 lines
1.6 KiB
C
52 lines
1.6 KiB
C
#include <c_KnuthShuffle.h>
|
|
#include "c_Random.h"
|
|
|
|
void c_KnuthShuffle(void* base, c_size_t num, c_size_t size) {
|
|
// 边界与防御性校验:元素少于2个或大小非法时无需洗牌
|
|
if (!base || num < 2 || size == 0) {
|
|
return;
|
|
}
|
|
|
|
c_Random_Init();
|
|
|
|
char* array_base = (char*)base;
|
|
|
|
// 采用局部栈分配缓冲区,避免堆内存分配开销,提升交换效率
|
|
// 256字节足够容纳绝大多数基础类型与常见的结构体
|
|
char temp_buf[256];
|
|
|
|
// 从后往前进行滑窗交换
|
|
for (c_size_t i = num; i > 1; i--) {
|
|
|
|
c_size_t current_idx = i-1;
|
|
|
|
// 安全地在 [0, i] 闭区间内抽取一个随机目标下标
|
|
// 依托您之前的去偏差 c_Random_RangeU64 确保概率绝对均等
|
|
c_size_t j = (c_size_t)c_Random_RangeU64(0, current_idx);
|
|
|
|
// 如果抽中自身,则无需原地交换
|
|
if (current_idx == j) {
|
|
continue;
|
|
}
|
|
|
|
// 计算需要交换的两个元素在内存中的绝对地址
|
|
char* elem_i = array_base + (current_idx * size);
|
|
char* elem_j = array_base + (j * size);
|
|
|
|
// 泛型就地内存交换 (In-place Swap)
|
|
c_size_t bytes_to_swap = size;
|
|
while (bytes_to_swap > 0) {
|
|
c_size_t chunk = (bytes_to_swap < sizeof(temp_buf)) ? bytes_to_swap : sizeof(temp_buf);
|
|
|
|
memcpy(temp_buf, elem_i, chunk);
|
|
memcpy(elem_i, elem_j, chunk);
|
|
memcpy(elem_j, temp_buf, chunk);
|
|
|
|
elem_i += chunk;
|
|
elem_j += chunk;
|
|
bytes_to_swap -= chunk;
|
|
}
|
|
}
|
|
}
|
|
|