How to fix this non-recursive odd-even-merge sort algorithm?

前端 未结 3 1421
南旧
南旧 2021-01-04 11:00

I was searching for non-recursive odd-even-merge sort algorithm and found 2 sources:

  • a book from Sedgewick R.
  • this SO question

Both alg

相关标签:
3条回答
  • 2021-01-04 11:07

    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.

    0 讨论(0)
  • 2021-01-04 11:13

    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);
    }
    
    0 讨论(0)
  • 2021-01-04 11:30

    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.

    0 讨论(0)
提交回复
热议问题