Given an array
[a1 a2 a3 ... an b1 b2 b3 ... bn c1 c2 c3 ...cn]
without using extra memory how do you reorder into an array
[开发者_如何学运维a1 b1 c1 a2 b2 c2 a3 b3 c3 ... an bn cn]
Your question can also be rephrased as 'How to do an in-place matrix transposition?'. To see why, imagine adding a newline after each subsequence in both of your arrays. This will turn the first array into an NxM matrix, and the second array into an MxN matrix.
Still, it is not trivial for non-square matrices. Please refer to the Wikipedia page on In-place matrix transposition for a comprehensive description of the problem and its solutions.
Assuming you mean O(1) memory (or depending on the model O(log n)) rather than no extra memory, a linear time in-place algorithm exists.
This paper: http://arxiv.org/abs/0805.1598 has an algorithm for the case when you have
a1 ... an b1 ... bn
and want to convert to
b1 a1 b2 a2 ... bn an
.
The paper also mentions that you can generalize this to other k-way shuffles. In your case, k = 3.
The algorithm in the paper will give the following:
Start with a1 a2 ... an b1 b2 ... bn c1 c2 ... cn
and convert to
c1 b1 a1 c2 b2 a2 ... cn bn an
Another pass through this, and you can easily get a1 b1 c2 a2 b2 c2 ... an bn cn
.
Now to generalize the algorithm in the paper, we need to pick a prime p, such that k is a primitive root of p^2.
For k = 3, p = 5 will do.
Now to apply the algorithm, first you need to find the largest m < n such 3m+1 is a power of 5.
Note: this will only happen when 3m+1 is an even power of 5. Thus you can actually work with powers of 25 when trying to find the m. (5^odd - 1 is not divisible by 3).
Once you find m,
You shuffle the array to be
[a1 a2 ... am b1 b2 ... bm c1 c2 ... cm] [a(m+1) ... an b(m+1) ... bn c(m+1) ... cn]
and then use the follow the cycle method(refer the paper) for the first 3m elements, using the powers of 5 (including 1 = 5^0) as the starting points of the different cycles) and do a tail recursion for the rest.
Now to convert
a1 a2 ... an b1 b2 ... bn c1 c2 ... cn
to
[a1 a2 ... am b1 b2 ... bm c1 c2 ... cm] [a(m+1) ... an b(m+1) ... bn c(m+1) ... cn]
you first do a cyclic shift to get
a1 a2 ... am [b1 b2 bm a(m+1) .. an] b(m+1) .. bn c1 c2 ... cn
(the elements in the square brackets are the ones that were shifted)
Then do a cyclic shift to get
a1 a2 ... am b1 b2 bm a(m+1) .. an [c1 c2 ..cm b(m+1) .. bn ] c(m+1) ... cn
And then a final shift to
a1 a2 ... am b1 b2 bm [c1 c2 ..cm a(m+1) .. an ] b(m+1) .. bn c(m+1) ... cn
Note that cyclic shift can be done in O(n) time and O(1) space.
So whole algorithm is O(n) time and O(1) space.
You can calculate each item's target position based on its index.
groupSize = N/3
group = i/groupSize
rank = i - group * groupSize
dest = rank * 3 + group
You can use this calculation with a cycle sort to put each element in its proper place in linear time. The only issue is tracking which items are already in place. All you need for that is N bits. With certain types of data, you can "steal" a bit from the data item itself. For instance you can use the high bit of ASCII data, or the low byte of word-aligned pointers.
Alternately, you can do it without any extra bits at the expense going to polynomial time. Reverse the calculation, so you can find the original source index of each item in the final array.
source = i % groupSize + groupSize * (i/groupSize) ; //integer division
Now walk forward through the array, swapping every item with the one from the source. The trick is that any time the source index is less than the current position (meaning it has already been swapped out), you need to follow the trail until you find its current location
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)]
You can do this for certain - just take cards ace, 2, ... 5 in 3 suits and put them in order.
First you take out the a2 card and put it aside. Then you move the b1 to the a2 position and shift all the cards up
Then you put back the a2 card and put in the shifted out position.
Then you take out the a3 card and puti taside Move the c1 to the a3 position and shift all the cards up.
Then put back the a3 card in the emptied position.
repeat until done.
The actual calculation of the indices is tricky but I believe a previous poster has done this.
精彩评论