简体   繁体   中英

how to generate Chase's sequence

In the draft section 7.2.1.3 of The art of computer programming, generating all combinations, Knuth introduced Algorithm C for generating Chase's sequence.

算法C

He also mentioned a similar algorithm (based on the following equation) working with index-list without source code (exercise 45 of the draft).

在此处输入图片说明

I finally worked out a c++ version which I think is quite ugly. To generate all C_n^m combination, the memory complexity is about 3 (m+1) and the time complexity is bounded by O(mn^m)

class chase_generator_t{
public:
    using size_type = ptrdiff_t;
    enum class GET : char{ VALUE, INDEX };

    chase_generator_t(size_type _n) : n(_n){}
    void choose(size_type _m){
        m = _m;
        ++_m;
        index.resize(_m);
        threshold.resize(_m + 1);
        tag.resize(_m);
        for (size_type i = 0, j = n - m; i != _m; ++i){
            index[i] = j + i;
            tag[i] = tag_t::DECREASE;
            using std::max;
            threshold[i] = max(i - 1, (index[i] - 3) | 1);
        }
        threshold[_m] = n;
    }
    bool get(size_type &x, size_type &y, GET const which){
        if (which == GET::VALUE) return __get<false>(x, y);
        return __get<true>(x, y);
    }
    size_type get_n() const{
        return n;
    }
    size_type get_m() const{
        return m;
    }
    size_type operator[](size_t const i) const{
        return index[i];
    }
private:
    enum class tag_t : char{ DECREASE, INCREASE };
    size_type n, m;
    std::vector<size_type> index, threshold;
    std::vector<tag_t> tag;

    template<bool GetIndex>
    bool __get(size_type &x, size_type &y){
        using std::max;
        size_type p = 0, i, q;
    find:
        q = p + 1;
        if (index[p] == threshold[q]){
            if (q >= m) return false;
            p = q;
            goto find;
        }
        x = GetIndex ? p : index[p];
        if (tag[p] == tag_t::INCREASE){
            using std::min;
        increase:
            index[p] = min(index[p] + 2, threshold[q]);
            threshold[p] = index[p] - 1;
        }
        else if (index[p] && (i = (index[p] - 1) & ~1) >= p){
            index[p] = i;
            threshold[p] = max(p - 1, (index[p] - 3) | 1);
        }
        else{
            tag[p] = tag_t::INCREASE;
            i = p | 1;
            if (index[p] == i) goto increase;
            index[p] = i;
            threshold[p] = index[p] - 1;
        }
        y = index[p];
        for (q = 0; q != p; ++q){
            tag[q] = tag_t::DECREASE;
            threshold[q] = max(q - 1, (index[q] - 3) | 1);
        }
        return true;
    }
};

Does any one has a better implementation, ie run faster with the same memory or use less memory with the same speed?

I think that the C code below is closer to what Knuth had in mind. Undoubtedly there are ways to make it more elegant (in particular, I'm leaving some scaffolding in case it helps with experimentation), though I'm skeptical that the array w can be disposed of. If storage is really important for some reason, then steal the sign bit from the a array.

#include <stdbool.h>
#include <stdio.h>

enum {
  N = 10,
  T = 5
};

static void next(int a[], bool w[], int *r) {
  bool found_r = false;
  int j;
  for (j = *r; !w[j]; j++) {
    int b = a[j] + 1;
    int n = a[j + 1];
    if (b < (w[j + 1] ? n - (2 - (n & 1)) : n)) {
      if ((b & 1) == 0 && b + 1 < n) b++;
      a[j] = b;
      if (!found_r) *r = j > 1 ? j - 1 : 0;
      return;
    }
    w[j] = a[j] - 1 >= j;
    if (w[j] && !found_r) {
      *r = j;
      found_r = true;
    }
  }
  int b = a[j] - 1;
  if ((b & 1) != 0 && b - 1 >= j) b--;
  a[j] = b;
  w[j] = b - 1 >= j;
  if (!found_r) *r = j;
}

int main(void) {
  typedef char t_less_than_n[T < N ? 1 : -1];
  int a[T + 1];
  bool w[T + 1];
  for (int j = 0; j < T + 1; j++) {
    a[j] = N - (T - j);
    w[j] = true;
  }
  int r = 0;
  do {
    for (int j = T - 1; j > -1; j--) printf("%x", a[j]);
    putchar('\n');
    if (false) {
      for (int j = T - 1; j > -1; j--) printf("%d", w[j]);
      putchar('\n');
    }
    next(a, w, &r);
  } while (a[T] == N);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM