重新排序数组元素

时间:2011-04-05 19:23:26

标签: algorithm

给定数组

[a1 a2 a3 ... an b1 b2 b3 ... bn c1 c2 c3 ...cn]

不使用额外的内存如何重新排序成数组

[a1 b1 c1 a2 b2 c2 a3 b3 c3 ... an bn cn]

4 个答案:

答案 0 :(得分:11)

您的问题也可以改为“如何进行就地矩阵换位?”。要了解原因,请假设在两个数组中的每个子序列之后添加换行符。这会将第一个数组转换为NxM矩阵,将第二个数组转换为MxN矩阵。

尽管如此,非方形矩阵并非易事。有关问题及其解决方案的详细说明,请参阅the Wikipedia page on In-place matrix transposition

答案 1 :(得分:6)

假设您的意思是O(1)内存(或取决于模型O(log n))而不是没有额外的内存,则存在线性时间就地算法。

本文:http://arxiv.org/abs/0805.1598有一个算法,当你有

a1 ... an b1 ... bn并希望转换为

b1 a1 b2 a2 ... bn an

本文还提到你可以将其推广到其他k-way shuffle。在你的情况下,k = 3。

本文中的算法将给出以下内容:

a1 a2 ... an b1 b2 ... bn c1 c2 ... cn开始并转换为

c1 b1 a1 c2 b2 a2 ... cn bn an

另一个传递,你可以轻松获得a1 b1 c2 a2 b2 c2 ... an bn cn

现在为了概括本文中的算法,我们需要选择素数p,这样k就是p ^ 2的原始根。

对于k = 3,p = 5将会这样做。

现在要应用算法,首先需要找到最大的m< n这样的3m + 1是5的幂。

注意:这只会在3m + 1是偶数 5的幂时发生。因此,当你试图找到m时,你实际上可以使用25的幂。 (5 ^奇数 - 1不能被3整除。)

找到m后,

你将数组洗牌为

[a1 a2 ... am b1 b2 ... bm c1 c2 ... cm] [a(m+1) ... an b(m+1) ... bn c(m+1) ... cn]

然后使用循环方法(参考论文)获取前3m元素,使用5的幂(包括1 = 5 ^ 0)作为不同循环的起点)并进行尾递归其余的。

现在转换 a1 a2 ... an b1 b2 ... bn c1 c2 ... cn

[a1 a2 ... am b1 b2 ... bm c1 c2 ... cm] [a(m+1) ... an b(m+1) ... bn c(m+1) ... cn]

首先进行循环转换

a1 a2 ... am [b1 b2 bm a(m+1) .. an] b(m+1) .. bn c1 c2 ... cn

(方括号中的元素是移位的元素)

然后进行循环移位以获得

a1 a2 ... am b1 b2 bm a(m+1) .. an [c1 c2 ..cm b(m+1) .. bn ] c(m+1) ... cn

然后最后转移到

a1 a2 ... am b1 b2 bm [c1 c2 ..cm a(m+1) .. an ] b(m+1) .. bn c(m+1) ... cn

请注意,循环移位可以在O(n)时间和O(1)空间中完成。

因此整个算法是O(n)时间和O(1)空间。

答案 2 :(得分:2)

您可以根据索引计算每个项目的目标位置。

groupSize = N/3
group = i/groupSize
rank = i - group * groupSize
dest = rank * 3 + group

您可以将此计算与循环排序一起使用,以便在线性时间内将每个元素放置在适当的位置。唯一的问题是跟踪哪些项目已经到位。你需要的只是N位。对于某些类型的数据,您可以从数据项本身“窃取”一些。例如,您可以使用高位ASCII数据或字对齐指针的低字节。


或者,您可以在没有任何额外位的情况下执行此操作,费用为多项式时间。反转计算,以便找到最终数组中每个项目的原始源索引。

source = i % groupSize + groupSize * (i/groupSize) ;  //integer division

现在向前走过数组,用源中的一个交换每个项目。诀窍是,只要源索引小于当前位置(意味着它已被换出),您需要跟踪路径,直到找到其当前位置

getSource(i):
   s = i % groupSize + groupSize * (i/groupSize)
   while (s<i)
      s = s % groupSize + groupSize * (s/groupSize)
   return s

shuffle:
for i in (0..N-1) 
   swap(a[i],a[getSource(i)]

答案 3 :(得分:0)

你可以肯定地做到这一点 - 只需将卡牌ace,2,... 5套装成三件套装并按顺序排列。

首先取出a2卡并将其放在一边。 然后将b1移动到a2位置并将所有卡向上移动

然后你放回a2卡并放入移出的位置。

然后你拿出a3卡和puti taside 将c1移动到a3位置并向上移动所有卡片。

然后将a3卡放回空位。

重复直到完成。

指数的实际计算是棘手的,但我相信之前的海报已经做到了这一点。