0

我需要一个计数器算法,它使用任意给定的数字进行计数。

我的代码与此类似:

static char digits[] = {'x','y','z'}; /* Arbitrary number of arbitrary digits. */
int i;
for(i=0; i<100; i++) {
    printf("%s\n", get_next());
}

我的预期输出:

x
y
z
yx
yy
yz
zx
zy
zz
yxx
yxy
yxz
yyx
yyy
yyz
yzx
yzy
yzz
zxx
... and so on

如您所见,我需要算法来实现get_next()功能,所以使用 C 语言不是重点。

为澄清起见,编辑 I:

我的 get_next() 函数可能与此类似:

char get_next() {
    static previous = digits[0];
    char *next_number;

    /* do something here using previous and digits[] */

    return next_number;
}

请注意,对生成下一个数字的函数使用get_next(void)ornext(previous_number)next(digits, previous_number)原型对我来说并不重要。

编辑二为澄清目的:

与上面的简单示例相比,我的真实场景更加复杂,我需要一个适用于任意数量任意数字的通用解决方案。

数字输入示例:

static char digits[] = {'a', 'b', 'c', ... 'z', '0', '1', ...}; /* Lots of digits */
static char digits[] = {'s','t','a','c','k','o','v','e','r'};   /* Arbitrary sequence */
4

4 回答 4

5

这很简单。您想转换为基数 digit_count,然后将数字转换为数字,而不是将数字转换为数字,而是索引到您的数组中。

要转换为任意基数,您需要除法和余数。

这是一个比我以前使用的更好的版本,因为它实际上创建了一个缓冲区(而不是打印出来),放弃了迭代的递归并且在 C 中而不是我以前的 C/Python 大杂烩。

因为它使用静态缓冲区,所以代码不是线程安全的。另请注意,如果数字太大,则不会检查代码是否下溢缓冲区。最后,它使用了一种技巧,将字符串从末尾构建到前面,并返回一个指向缓冲区中间的指针,因此它不必在末尾反转数字。

char *getnum(int x)
{
    static char buffer[1024];
    int idx = 1024;

    buffer[--idx] = '\0';

    if (x == 0)
        buffer[--idx] = digits[0];
    else
    {
        while (x != 0)
        {
            buffer[--idx] = digits[x % digit_count];
            x /= digit_count;
        }
    }    

    return buffer + idx;
}
于 2009-12-22T07:01:21.590 回答
2

您的问题可以分为两部分:

  1. 将整数转换为任意基数的表示形式n,以及
  2. 给定n符号,打印上面的表示。

第二部分显然很容易。如果您在给定的基数中有一个数字的表示形式,并且您想在这样的基数中使用符号,那么将它们打印出来只是在循环中打印内容。

为了得到一个给定基数的整数表示,我们将使用一个ints 数组,其中值表示数字,索引表示位置。我们还需要存储有效位数。此外,我们假设我们只处理正数,因为这似乎是您在问题中的建议。

#define MAX 128 /* maximum number of digits in the final representation */

/* abstract representation of a number in a given base.
   `n` is the number of valid digits in the representation, and
   `digits` stores the digits in reverse order */
struct rep {
    int digits[MAX]; /* change as needed, or dynamically allocate */
    size_t n;
};

然后,让我们编写一个函数来将数字转换为其表示形式。由于返回反向表示更容易,我们将返回它,然后也以相反的顺序打印:

/* convert a number `n` to its (reversed) representation in base `base`,
   and return the result in `ret`. */
void convert(int n, size_t base, struct rep *ret)
{
    size_t i = 0;
    do {
        ret->digits[i++] = n % base;
        n /= base;
    } while (n > 0 && i < MAX);
    ret->n = i;
}

完成此操作后,让我们编写一个函数来打印表示:

/* return a string representation of `num` in base `ndigits`, with `digits`
   representing the symbols */
char *next(const char *digits, size_t ndigits, int num)
{
    struct rep r;
    static char ret[MAX+1];
    size_t i;
    convert(num, ndigits, &r);
    if (r.n == MAX)
        return NULL;
    for (i=r.n; i; --i)
        ret[r.n-i] = digits[r.digits[i-1]];
    ret[r.n-i] = 0;
    return ret;
}

然后,我们可以编写我们的驱动程序:

int main(void)
{
    const char digits[] = {'x','y','z'};
    size_t ndigits = sizeof digits / sizeof digits[0];
    int i;
    for (i=0; i < 100; i++) {
        char *data = next(digits, ndigits, i);
        if (data)
            printf("%s\n", data);
        else
            fprintf(stderr, "%d, error converting\n", i);
    }
    return 0;
}

我已经写过上面的内容convertnext以便它们彼此独立(除了我使用反向表示的明显简化之外)。这使得在其他程序中使用它们变得很容易。

于 2009-12-22T09:03:10.657 回答
0
char *get_next()
{
  static char str[10];
  static int i=0;
  int radix = 3; // size of array
  itoa(i,str,radix); // create base-3 representation
  char *p = &str[0];
  while( *p )
  {
    *p = digits[*p-'0']; // convert to the xyz scheme, breaks if radix>10
    p++;
  }
  i++;
  return str;
}
于 2009-12-22T06:54:03.553 回答
0

看起来get_next你不需要重载operator++. 这导致了下一个推导,即这个东西应该是一个单独的对象。

我会将“数字”转换为十进制,然后对它们进行操作,然后将它们转换回来。

于 2009-12-22T23:05:06.457 回答