简体   繁体   English

如何生成大通的序列

[英]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. 在计算机编程领域的草案第7.2.1.3节中,生成所有组合,Knuth引入了用于生成Chase序列的算法C。

算法C

He also mentioned a similar algorithm (based on the following equation) working with index-list without source code (exercise 45 of the draft). 他还提到了一种类似的算法(基于以下等式),该算法适用于没有源代码(草案的练习45)的索引列表。

在此处输入图片说明

I finally worked out a c++ version which I think is quite ugly. 我终于找到了一个我认为很丑陋的C ++版本。 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) 要生成所有C_n ^ m组合,内存复杂度约为3(m + 1),时间复杂度由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. 我认为下面的C代码更接近Knuth的想法。 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. 毫无疑问,有一些方法可以使它变得更优雅(特别是,我会留下一些脚手架以防实验失败),尽管我怀疑可以处理数组w If storage is really important for some reason, then steal the sign bit from the a array. 如果存储是出于某种原因真的很重要,然后盗取符号位a阵列。

#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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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