如果我只需要对由ASCII字符组成的字符串进行排序,那么想知道使用最重要的vs.s之间有什么区别。最不重要的基数排序?我认为他们应该有相同的结果,但是下面链接中的以下陈述会让我感到困惑,如果有人可以帮助澄清,那就太棒了。
https://en.wikipedia.org/wiki/Radix_sort
最高位数(MSD)基数排序可用于按字典顺序对键进行排序。与最低有效位(LSD)基数排序不同,最重要的数字基数排序不一定保留重复键的原始顺序。
提前谢谢, 林答案 0 :(得分:5)
LSD基数排序可以在每次传递后在逻辑上连接已排序的二进制数(如果使用计数/基数排序,则将它们视为单个二进制数)。 MSD基数排序必须在每次传递后独立地递归排序每个bin。如果按字节排序,第一次传递后为256个二进制位,第二次传递后为65536个二进制位,第三次传递后为16777216(1600万个)二进制位,....
这就是旧卡分类器首先对数据LSD进行排序的原因。链接到其中一个实际的视频。这些卡片被送入并向下滑入滑槽。在视频中,卡片分类器将卡片放入垃圾箱中#0; 0"到" 9"然后操作员从0箱中取出卡,然后从1箱中取出卡并将它们放在0箱卡的顶部(后面),然后将2个箱卡放在后面。甲板,等等,"连接"箱子里的卡片。对于大型卡片组,卡片分拣机上方将设置每个箱子上方的架子,以便在甲板太大而无法用手握住时放置卡片。
http://www.youtube.com/watch?v=jJH2alRcx4M
示例C ++ LSD基数排序,用于32位无符号整数,其中每个"数字"是一个字节。大多数代码生成一个计数矩阵,这些计数矩阵被转换为标记可变大小区间之间边界的索引。实际的基数排序在最后一个嵌套循环中。
// a is input array, b is working array
uint32_t * RadixSort(uint32_t * a, uint32_t *b, size_t count)
{
size_t mIndex[4][256] = {0}; // count / index matrix
size_t i,j,m,n;
uint32_t u;
for(i = 0; i < count; i++){ // generate histograms
u = a[i];
for(j = 0; j < 4; j++){
mIndex[j][(size_t)(u & 0xff)]++;
u >>= 8;
}
}
for(j = 0; j < 4; j++){ // convert to indices
m = 0;
for(i = 0; i < 256; i++){
n = mIndex[j][i];
mIndex[j][i] = m;
m += n;
}
}
for(j = 0; j < 4; j++){ // radix sort
for(i = 0; i < count; i++){ // sort by current lsb
u = a[i];
m = (size_t)(u>>(j<<3))&0xff;
b[mIndex[j][m]++] = u;
}
std::swap(a, b); // swap ptrs
}
return(a);
}
答案 1 :(得分:2)
令你困惑的部分是几乎所有LSD基数排序都保留了重复键的顺序。那是因为他们依靠这个属性来工作。例如,如果您有2次这样的迭代,首先排序一个位置,然后排序十位:
22 21 11
21 -> 11 -> 21
11 22 22
当我们按十位排序时,我们需要保留我们在按1排序时得到的打破平局顺序,这样即使它们在10s位置具有相同的数字,21和22也会以正确的顺序出现。如果你实现第一种排序(按一种方式),你拥有来执行所有其他排序(以及为什么不呢?),那么排序是稳定的。
MSD基数排序可以使用与LSD基数排序相同的排序步骤编写,在这种情况下它也将是稳定的。但是,还有其他通常更有效的方法来实现没有此属性的MSD基数排序。
不保留订单或重复项的MSD-第一基数排序通常是就地的,即它们无需分配单独的数组来保存已排序的元素。
请注意,如果您只是通过比较ASCII代码点来对字符串列表进行排序,则这些都没有任何区别。 “保留重复键的顺序”仅在附加了额外信息时才有意义。例如,如果键具有关联的值,或者您是以与案例无关的方式排序,并且您希望“Abe”和“abE”以与它们相同的顺序排出。