我有一些来自硬件的数据。数据以32字节为单位,可能有数百万个块。数据块按以下方式分成两半(字母是一个块):
A C E G I K M O B D F H J L N P
或编号为
0 2 4 6 8 10 12 14 1 3 5 7 9 11 13 15
首先是所有具有偶数索引的块,然后是奇数块。是否有专门的算法来正确地重新排序数据(按字母顺序排列)?
约束主要是空间。我不想再分配另一个缓冲区来重新排序:再多一个块。但我还想保持低移动次数:一个简单的快速排序就是O(NlogN)。对于这种特殊的重新排序情况,O(N)中是否有更快的解决方案?
答案 0 :(得分:7)
由于这些数据总是以相同的顺序排列,因此根本不需要经典意义上的排序。您不需要进行任何比较,因为您事先已经知道了两个给定数据点中的哪一个。
相反,您可以直接在数据上生成排列。如果将其转换为循环形式,则会准确地告诉您要进行哪些交换,将置换数据转换为有序数据。
以下是您的数据示例:
0 2 4 6 8 10 12 14 1 3 5 7 9 11 13 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
现在计算逆(我将跳过这一步,因为我在这里很懒,相反我上面给出的排列实际上已经是倒数)。
这是循环形式:
(0)(1 8 4 2)(3 9 12 6)(5 10)(7 11 13 14)(15)
因此,如果您想重新排序这样的结构序列,您可以
# first cycle
# nothing to do
# second cycle
swap 1 8
swap 8 4
swap 4 2
# third cycle
swap 3 9
swap 9 12
swap 12 6
# so on for the other cycles
如果您已经为逆而不是原始排列做了这个,那么您将获得具有经过验证的最小交换次数的正确序列。
修改强>:
有关此类内容的详细信息,请参阅TAOCP中的“排列”一章。
答案 1 :(得分:3)
所以你有数据以
这样的模式进入a 0 a 2 a 4 ... a 14 a 1 a 3 a 5 ... a 15
并且您希望将其排序为
b 0 b 1 b 2 ... b 15
通过一些重新排序,排列可以写成:
a 0 - > B'的子> 0 子>
a 8 - > B'的子> 1 子>
a 1 - > B'的子> 2 子>
a 2 - > B'的子> 4 子>
a 4 - > B'的子> 8 子>
a 9 - > B'的子> 3 子>
a 3 - > B'的子> 6 子>
a 6 - > B'子> 12 子>
a 12 - > B'的子> 9 子>
a 10 - > B'的子> 5 子>
a 5 - > B'的子> 10 子>
a 11 - > B'的子> 7 子>
a 7 - > B'的子> 14 子>
a 14 - > B'的子> 13 子>
a 13 - > B'的子> 11 子>
a 15 - > B'的子> 15 子>
因此,如果您想在临时t
中仅使用一个块额外空间对其进行排序,则可以使用
t = a8; a8 = a4; a4 = a2; a2 = a1; a1 = t
t = a9; a9 = a12; a12= a6; a6 = a3; a9 = t
t = a10; a10 = a5; a5 = t
t = a11; a11 = a13; a13 = a14; a14 = a7; a7 = t
编辑:
一般情况(对于N!= 16),如果它在O(N)中是可解的,实际上是一个有趣的问题。我怀疑循环始终以满足p < N/2 && N mod p != 0
的素数开始,并且索引具有像i n + 1 = 2i n mod N的重复,但我我无法证明这一点。如果是这种情况,导出O(N)算法是微不足道的。
答案 2 :(得分:1)
也许我是误会,但如果订单总是相同那么你可以“预编程”(即避免所有比较)最佳解决方案(这将是具有最小交换数量的交换从ABCDEFGHIJKLMNOP的字符串移动到哪一个,对于这么小的东西,你可以手工解决 - 见LiKao的回答)。
答案 3 :(得分:0)
我更容易用数字标记你的集合:
0 2 4 6 8 10 12 14 1 3 5 7 9 11 13 15
从14开始,将所有偶数移动到位(8个交换)。你会得到这个:
0 1 2 9 4 6 13 8 3 10 7 12 11 14 15
现在你需要另外3个掉期(9个带3个,7个带13个,11个带13个移动7个)。
共有11次掉期。不是一般解决方案,但它可以给你一些提示。
答案 4 :(得分:0)
您还可以将预期的排列视为地址位的混乱`abcd&lt; - &gt; dabc'(用abcd表示索引的各个位)如:
#include <stdio.h>
#define ROTATE(v,n,i) (((v)>>(i)) | (((v) & ((1u <<(i))-1)) << ((n)-(i))))
/******************************************************/
int main (int argc, char **argv)
{
unsigned i,a,b;
for (i=0; i < 16; i++) {
a = ROTATE(i,4,1);
b = ROTATE(a,4,3);
fprintf(stdout,"i=%u a=%u b=%u\n", i, a, b);
}
return 0;
}
/******************************************************/
答案 5 :(得分:-2)
那是count sort我相信