【发布时间】:2019-06-03 18:16:47
【问题描述】:
我正在阅读 Zed A. Shaw 的书Learn C The Hard Way,我正在查看他对基数排序算法的实现。
这是他的代码:
#define ByteOf(x, y) (((u_int8_t *)x)[y])
static inline void radix_sort(short offset, uint64_t max,
uint64_t * source, uint64_t * dest)
{
uint64_t count[256] = { 0 };
uint64_t *cp = NULL;
uint64_t *sp = NULL;
uint64_t *end = NULL;
uint64_t s = 0;
uint64_t c = 0;
// Count occurences of every byte value
for (sp = source, end = source + max; sp < end; sp++) {
count[ByteOf(sp, offset)]++;
}
// transform count into index by summing
// elements and storing them into same array.
for (s = 0, cp = count, end = count + 256; cp < end; cp++) {
c = *cp;
*cp = s;
s += c;
}
// fill dest with right values in the right place
for (sp = source, end = source + max; sp < end; sp++) {
cp = count + ByteOf(sp, offset);
printf("dest[%d] = %d\n", *cp, *sp);
dest[*cp] = *sp;
++(*cp);
}
}
以上只是一个辅助函数。他的实际基数排序在这里完成:
void RadixMap_sort(RadixMap * map)
{
uint64_t *source = &map->contents[0].raw;
uint64_t *temp = &map->temp[0].raw;
radix_sort(0, map->end, source, temp);
radix_sort(1, map->end, temp, source);
radix_sort(2, map->end, source, temp);
radix_sort(3, map->end, temp, source);
}
这是他定义的结构:
typedef union RMElement {
uint64_t raw;
struct {
uint32_t key;
uint32_t value;
} data;
} RMElement;
typedef struct RadixMap {
size_t max;
size_t end;
uint32_t counter;
RMElement *contents;
RMElement *temp;
} RadixMap;
我可以理解内联函数radix_sort 中的前两个 for 循环。据我了解,第一个函数只是简单地计算字节值,第二个函数基本上是制作一个累积频率表,其中每个条目是之前条目的总和。
我仍然无法理解 ByteOf(x, y) 宏和第三个 for 循环。我已经尝试阅读 Wikipedia page 的基数排序,我阅读了使用 C++ 实现的 another article。但是,这些文章中写的代码与他写的代码不匹配。
我了解基数排序原则上的工作原理。基本上,我们根据每个数字对其进行分组,为我们遇到的每个新数字重新安排分组。例如,要对数组[223, 912, 275, 100, 633, 120, 380] 进行排序,首先将它们按个位数字分组,得到[380, 100, 120]、[912]、[633, 223]、[275]。然后你对十位和一百位做同样的事情,直到你用完数字。
任何解释他的代码的帮助将不胜感激。 谢谢。
【问题讨论】:
-
我认为这是一个以 256 为基数的基数排序,而不是您习惯看到的以 10 为基数的排序(来自您的链接文章)。这样做的好处是您可以通过查看数字的字节(这是
ByteOf的用途)轻松地将值分组到存储桶中,而不是使用除法和模数。 -
那么让我看看我是否理解
ByteOf。基本上,ByteOf采用uint64_t指针并将其转换为字节数组 (uint8_t)。然后,访问索引y处的字节。这是ByteOf在做什么吗?
标签: c radix-sort