I was searching for non-recursive odd-even-merge sort algorithm and found 2 sources:
Both alg
I think I found a solution. I checked it for length = 2, 4, 8, 16
.
Here is my code:
void sort(int length)
{ int G = log2ceil(length); // number of groups
for (int g = 0; g < G; g++) // iterate groups
{ int B = 1 << (G - g - 1); // number of blocks
for (int b = 0; b < B; b++) // iterate blocks in a group
{ for (int s = 0; s <= g; s++) // iterate stages in a block
{ int d = 1 << (g - s); // compare distance
int J = (s == 0) ? 0 : d; // starting point
for (int j = J; j+d < (2<<g); j += 2*d) // iterate startpoints
{ for (int i = 0; i < d; i++) // shift startpoints
{ int x = (b * (length / B)) + j + i; // index 1
int y = x + d; // index 2
printf("%2i cmp %2i\n", x, y);
}
}
}
}
}
This solution introduces a fifth for-loop to handle subblocks in a group. The j loop has a changed start and abort value to handle odd counts of post merge steps without generating doubled compare steps.
This is a fixed non-recursive subroutine.
void sort(int n)
{
for (int p = 1; p < n; p += p)
for (int k = p; k > 0; k /= 2)
for (int j = k % p; j + k < n; j += k + k)
//for (int i = 0; i < n - (j + k); i++) // wrong
for (int i = 0; i < k; i++) // correct
if ((i + j)/(p + p) == (i + j + k)/(p + p))
printf("%2i cmp %2i\n", i + j, i + j + k);
}
or
void sort(int n)
{
for (int p = 1; p < n; p += p)
for (int k = p; k > 0; k /= 2)
for (int j = 0; j < k; j++)
for (int i = k % p; i + k < n; i += k + k)
if ((i + j)/(p + p) == (i + j + k)/(p + p))
printf("%2i cmp %2i\n", i + j, i + j + k);
}
The following code works for arrays of any size and isn't recursive. It is a straight port from the implementation of the corresponding function in Perl's Algorithm::Networksort
module. The implementation happens to correspond to the algorithm as described by Knuth in The Art of Computer Programming, vol 3 (algorithm 5.2.2M). It doesn't help to actually fix your algorithm, but it at least gives you a working non-recursive implementation of Batcher's odd-even mergesort with only three nested loops :)
#include <math.h>
#include <stdio.h>
void oddeven_merge_sort(int length)
{
int t = ceil(log2(length));
int p = pow(2, t - 1);
while (p > 0) {
int q = pow(2, t - 1);
int r = 0;
int d = p;
while (d > 0) {
for (int i = 0 ; i < length - d ; ++i) {
if ((i & p) == r) {
printf("%2i cmp %2i\n", i, i + d);
}
}
d = q - p;
q /= 2;
r = p;
}
p /= 2;
}
}
If you can get your hands on a copy of The Art of Computer Programming, vol 3, you will have a nice explanation of how and why the algorithm works, as well as a few additional details.