假设我有一个隔行扫描数据数组,例如1a2b3c4d5e,我想将它解交错到一个看起来像12345abcde的数组(没有临时缓冲区)。这样做的最快方法是什么?
到目前为止我所拥有的是
template<typename T>
void deinterlace(T* arr, int length){
if(length<=1) return;
int i = 1;
for(i = 1; i*2<length; i++){
//swap i with i*2
T temp = arr[i];
arr[i] = arr[i*2];
arr[i*2] = temp;
}
deinterlace(arr+i, length-i);
}
,遗憾的是不适用于数量不大于2的数组
编辑:无论如何,这个算法在2的较大权力下失败,所以我猜我再次在0号方位
编辑2 :我找到了一个nlogn算法,给定一个O(n)数组旋转函数,或者初始大小是2的幂
的工作原理如下:
1a2b3c4d5e6f7g,“chunk size”= 1 initial,
分成块大小* 4组 1a2b 3c4d 5e6f 7g
交换每组的内部2块 12ab 34cd 56ef 7g
重复chunk size = chunk size * 2
12ab34cd 56ef7g(读数:56 ef 7 g) - &gt; 1234abcd 567efg
1234abcd567efg - &gt; 1234567abcdefg
template<typename T>
void deinterlace(T* arr, int length, int group_ct = 1){
if(group_ct*2 >= length) return;
for(int i = 0; i<length; i+=group_ct*4){
int rot_count = group_ct;
int i1 = i + group_ct;
int i2 = i+group_ct*4 - group_ct;
if(i2+group_ct > length){
i2 = i1 + (length-i1)/2+group_ct/2;
}
rotate(arr, i1, i2, group_ct);
}
deinterlace(arr, length, group_ct * 2);
}
编辑3 我猜正确的术语是deinterleave,而不是deinterlace
答案 0 :(得分:11)
这实质上是一个矩阵转置问题。你的阵列
[1 a]
[2 b]
[3 c]
[4 d]
如果表示为向量(通过首先读取行),等同于1, a, 2, b, 3, c, 4, d
。该矩阵的转置是:
[1 2 3 4]
[a b c d]
相当于1, 2, 3, 4, a, b, c, d
。
有一个wikipedia page处理一般情况下的就地矩阵转置。我想,非方阵的算法可以直接应用。
你可以使用慢速(不确定是否为O(n ^ 2)或更差,并且它是迟到的)算法。我们的想法是将子阵列从位置i
旋转到位置2*i
。例如:
START: 1a2b3c4d5e6f
1(a2)... -> 1(2a)...
12(ab3)... -> 12(3ab)...
123(abc4)... -> 123(4abc)...
1234(abcd5)... -> 1234(5abcd)...
12345(abcde6)... -> 12345(6abcde)..
123456(abcdef) -> DONE
数组的第一个成员是索引0.在步骤1中,选择子数组a[1:2]
,然后向右旋转(所有成员转到下一个位置,最后一个转到开始)。下一步,选择a[2:4]
,然后旋转,等等。确保不要旋转最后一个子阵列a[n/2:n]
。
最后一个选项,如果你不需要为性能进行批量操作(例如memcpy
),则提供一个访问器函数,并转换索引而不是移动任何字节。编写这样的函数几乎是微不足道的:如果index小于max/2
,则返回2*index
的条目,否则返回2*(index-max/2)+1
的条目。
答案 1 :(得分:-1)
如果不关心结果数组的顺序,我能想到的最快方法是使用'head'和'tail'索引进行连续交换。
int head = 1;
int tail = length - 2;
while (head < tail)
{
T temp = arr[head];
temp = arr[head];
arr[head] = arr[tail];
arr[tail] = temp;
head += 2;
tail -= 2;
}
对于您的示例案例,在2次迭代后结果将是15243cbdae。