What you have is an N X 2 matrix represented in a one dimentional array that you want transposed into a 2 X N array.
For example your list:
a1, b1, a2, b2, ... an, bn
can just as well be represented as the matrix:
x1,1, x1,2, x2,1, x2,2, ... xn,1, xn,2
Which you want to transpose to become:
x1,1, x2,1, ... xn,1, x1,2, x2,2, ... xn,2
The in place matrix transposition algorithm will do the job.
EDIT
Ok let me spell it out. Try the following bit of code:
i = 0 /* linear array index */
do j = 1 to c /* j = 1 to virtural columns */
do k = 1 to r /* k = 1 to virtural rows */
i = i + 1
sp = (k - 1) * c + j
do while sp < i
ct = (sp - 1) % r + 1
rt = sp - (ct - 1) * r
sp = (rt - 1) * c + ct
end
if i \= sp then say 'swap('i',' sp')' /* swap elements */
end
end
This will print out the array elements that need to be swapped. This will work for any sized matrix represented in a linear array where the elements are arranged by column then row. Using an N X 2 martix, the elements would be arranged as follows:
x1,1, x1,2, x2,1, x2,2, ... xn,1, xn,2
The algorithm prints out the elements that need to be swapped to yield an array orderd as follows:
x1,1, x2,1, ... xn,1, x1,2, x2,2, ... xn,2
For example, start with r = 4, c = 2 and the array:
A1, B1, A2, B2, A3, B3, A4, B4
Requires the following swaps:
swap(2, 3)
swap(3, 5)
swap(4, 7)
swap(6, 7)
to become:
A1, A2, A3, A4, B1, B2, B3, B4
This algorithm is efficient in both space and time.
Big-O
My O-foo is not great but I will give it a shot...
The matrix contains 2 columns ('A' and 'B') and 'M' rows. To represent this as
a linear array we need 2M elements. Lets call that number N (the size of the linear array).
The algorithm has two iteration loops, one for 'r' (rows) and one for 'c' (columns).
Total iterations is then r * c which in our case comes down to 2M = N. So far so good.
The wild card is the inner DO WHILE
loop. How many iterations does it require for a given number of rows?
The answer may be: Quite a few.
Based on some empirical results (shown below) it looks like the number of DO WHILE
iterations
is a complex function involving 'r' when 'c' = 2 (or probably any value of 'c').
I do not have enough O-foo to figure out exactly what this function is.
However, it should not get any worse than N3 (one complete 'chase' through the matrix, N2, times
every element, N). Not a good picture - in theory. So I guess that makes it O(N3)? This may be
a non O(N) algorithm, but in practical terms appears to perform close to O(N) given the bits of
empirical data below. I'm kind of lost at this point - comments welcome!
One observation about the DO WHILE
loop though: It is using integer based math on simple variables (no array
references required). If you are going non-linear this has got
to be the 'cheapest' place to do it!
How many swaps are required? The number of swaps is limited to one per iteration through the outer
two loops, which is at most N times. The number of swaps is in line with an O(N) performance.
My guess is that this is a non O(N) algorithm, but does appear to have reasonable behavior
for 2 column matrices of moderate size.
Here are some empirical results for various 2 column matrix sizes:
Rows Loops per row
========== =============
500 9
1,000 19
1,500 21
2,000 12
2,500 18
3,000 23
3,500 26
1,000,000 30
2,000,000 40
3,000,000 45
10,000,000 59
20,000,000 39
30,000,000 60
The 'loops per row' grow with row count, but not at an alarming rate. The danger is of hitting some 'sweet' spot where it goes exponential - but I don't know if it really has that potential.
My advice to Mgccl would be to benchmark this algorithm over the range of row counts that are
typical in his application then decide if it would yield an acceptable performance relative to other
algorithm benchmarks. Big-O analysis
is interesting, but results over an operational range of data are what count.
Last kick at the can: Why does this algorithm work?
Transpose a matrix represented in linear form:
Given matrix X having M rows and N columns.
Lay X out into a linear array in row major order. The
array will be organized as follows:
11, 12, 13, ... 1N, 21, 22, 23, ... 2N, ... M1, M2, M3 ... MN
A notation describing each element in the linear array
is:
X[i,r,c]
where: i is the linear array index for element X
r is the row number for element X
c is the column number for element X.
Using this notation,
an array in row major order can be generated as:
i = 0
for j = 1 to M /* Row counter */
for k = 1 to N /* Column counter */
i = i + 1 /* array index of element j, k */
say 'X['i','j',k']'
end
end
Note that given values for j (row) and k (column), i may be calculated as:
i = (j - 1) * N + k
The transpose of matrix X is constructed by exchanging the elements
X[i,r,c] with X[t,c,r] over the range of r and c. In essence we exchange
all row variables for column variables. Using the notation
described above, this amounts to exchanging linear array elements:
exchange(X[i,r,c], X[t,c,r])
where: i = (r - 1) * N + c
t = (c - 1) * M + i
The number of exchanges required to transpose the matrix will be less than
M * N because at most one exchange is ever required to place an element into its correct
position. In some cases an exchange will not be required because the
element is already 'in place'. For example the first and last elements of X
never need exchanging.
By proceeding through the linear array by increasing i, we know that as long as
none of the exchanges involve elements where i > t, the matrix will be in
column major order for all elements having indexes less than or equal to i.
Whenever i > t, it means that a prior exchange took place at index t.
The element at t was exchanged as indicated above placing it
at some new position t'. Given an index t, we may calculate the row major index t'
as well as the row and column numbers associate with it as follows:
c' = (t - 1) % M + 1
r' = t - (c' - 1) * M
t' = (r' - 1) * N + c'
Again, if t' is less than i, it means that this element was exchanged too and we must
continue with another round of calculations. Set t to the calculated t' and repeat.
Eventually, i will become <= t and
the exchange may be done. Basically we 'chase' the element through all of its
prior exchanges until we find it at i or to the right of i in the linear
array.
Repeat this cycle for each element in the linear array and the matrix will have
been transposed.