任意数字计数器

时间:2009-12-22 06:30:28

标签: c algorithm counter state-machine

我需要一个计数器 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语言不是重点。

编辑我以澄清目的:

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

4 个答案:

答案 0 :(得分:5)

这很简单。您希望转换为base digit_count,然后将数字转换为数字,而不是将数字转换为数组。

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

这是一个比我之前使用的版本更好的版本,因为它实际上创建了一个缓冲区(而不是将其打印出来),删除迭代的递归,而不是我以前的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;
}

答案 1 :(得分:2)

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

  1. 将整数转换为其在任意基础n
  2. 中的表示形式
  3. 给出n符号,打印上面的表示。
  4. 第二部分显然很容易。如果您在给定的基础中有一个数字的表示,以及您想要在这样的基础中使用的符号,那么将它们打印出来只是在循环中打印。

    要获取给定基数中的整数表示,我们将使用int s的数组,其中值表示数字,而索引表示位置。我们还需要存储有效数字的数量。此外,我们假设我们只处理正数,因为这是您在问题中的建议。

    #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,以便它们彼此独立(除了我正在使用反向表示的明显简化)。这样可以很容易地在其他程序中使用它们。

答案 2 :(得分: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;
}

答案 3 :(得分:0)

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

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