【问题标题】:Arbitrary Digit Counter任意数字计数器
【发布时间】:2009-12-22 06:30:28
【问题描述】:

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

我的代码是这样的:

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)next(previous_number)next(digits, previous_number) 原型作为生成下一个数字的函数对我来说并不重要。

为澄清目的而编辑 II:

与上面的简单示例相比,我的实际情况更加复杂,我需要一个通用的解决方案,该解决方案适用于任意数字任意数字

数字输入示例:

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 */

【问题讨论】:

  • 您确定要get_next(),而不是get(i),将i 转换为您自己的编号函数吗?
  • 你不想拥有 x,y,z,xx,xy,xz,yx,yy,yz,zx,zy,zz,xxx,xxy,...?
  • paxdiablo:我不认为他有,x 是这个计数系统中的 0 等价物。就像您在十进制的910 之间没有00
  • @paxdiablo:我认为给出的例子是正确的。例如,假设 x、y、z 分别为 0、1、2。
  • 同意。 get_next() 怎么知道digits,或者最后返回的组合是什么(假设你不想要静态)

标签: c algorithm counter state-machine


【解决方案1】:

这很简单。您想转换为基本 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;
}

【讨论】:

  • 这就是我要找的,我想它会是递归的,但我找不到这么优雅的解决方案,谢谢。顺便说一句,您是 Python 还是 Pascal 程序员,您在大括号之前省略了分列(这对 C 来说是非法的)。
  • 这绝对是最简单和最好的方法。鉴于它已经使用了静态缓冲区,它还不如开始“静态 int next_x = 0; int x = next_x++;”而不是传入 x,并被称为 get_next(),如果那是真正想要的。
【解决方案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,以便它们彼此独立(除了我使用反向表示的明显简化之外)。这使得在其他程序中使用它们变得很容易。

【讨论】:

    【解决方案3】:
    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;
    }
    

    【讨论】:

    • 您假设数字在 ASCII 中是连续的。 digits = {'a', 'h', 't', 'z'} 呢?
    • 您的解决方案是针对特定位数的,我需要“任意位数的任意位数”的解决方案,我可以使用 255 作为基数(itoa 的第三个参数)吗?
    • @eyazici:对于 > 36 的值,您必须滚动自己的 itoa,但本质是状态机只是变量“i”。
    • @abyx:从itoa出来的数字是连续的,然后作为数字的索引,不做任何假设,只是一个查找表。
    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 2022-10-13
      • 1970-01-01
      • 2013-08-16
      • 2014-06-06
      • 1970-01-01
      • 1970-01-01
      • 2021-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多