performancealgorithmdata-structurestime-complexityin-place

Move all odd positioned element to left half and even positioned to right half in-place


Given an array with positive and negative integers, move all the odd indexed elements to the left and even indexed elements to the right.

The difficult part of the problem is to do it in-place while maintaining the order.

e.g.

7, 5, 6, 3, 8, 4, 2, 1

The output should be:

5, 3, 4, 1, 7, 6, 8, 2

If the order didn't matter, we could have been used partition() algorithm of quick sort.

How to do it in O( N )?


Solution

    1. Get largest sub-array having size 3k+1
    2. Apply cycle leader algorithm to the parts of this sub-array, starting from positions 1, 3, 9, ... 3k-1: move element to its proper position in sub-array (even-indexed elements to the left of sub-array, odd-indexed - to the right), the replaced element should be also moved to its proper position, etc. until this procedure comes back to the starting position. This paper gives number-theoretic explanation why such selection of starting positions shuffles sub-array to the correct order.
    3. Process the remaining parts of the array recursively, using steps 1 and 2.
    4. Now we only need to join the reordered parts together. Start with the smaller sub-arrays at the end of the whole array. To exchange sub-array halves, use reverse algorithm: reverse(reverse(a), reverse(b)); or, for sub-array halves of equal size, use pair-wise swaps.
    5. Now all even-positioned elements are on the left. To get them on the right, as required, exchange elements i and i+N/2 for all i = 0 .. N/2-1.

    Algorithm is in-place, time complexity is O(N).

    Example:

    0 1 2 3 4  5 6 7 8 9   10 11 (the original array)
    0 1 2 3 4  5 6 7 8 9 # 10 11 (split to sub-arrays)
    0 2 4 3 8  1 6 5 7 9 # 10 11 (first cycle leader iteration, starting with 1)
    0 2 4 6 8  1 3 5 7 9 # 10 11 (second cycle leader iteration, starting with 3)
    0 2 4 6 8  9 7 5 3 1 # 10 11(2nd half of 1st part& 1st half of 2nd part reversed)
    0 2 4 6 8 10 1 3 5 7    9 11 (both halves reversed together)
    

    Variation of this algorithm, that does not need step 5:

    Here is different O(N log N) in-place algorithm, which does not need number-theoretic proofs:

    1. Reinterpret your array as a sequence of single-element 2*2 matrices, transpose these matrices.
    2. Reinterpret the result as a sequence of two-element 2*2 matrices and transpose them.
    3. Continue while matrices size is less than the array size.
    4. Now we only need to join the reordered parts together (exactly as in previous algorithm).
    5. Exchange elements of left and right halves of the array (exactly as in previous algorithm).

    Example:

    0  1   2 3   4 5   6 7  (the original array)
    [0 2] [1 3] [4 6] [5 7] (first transposition)
    [0 2] [4 6] [1 3] [5 7] (second transposition)
    

    This problem is just a special case of the In-place matrix transposition.