【问题标题】:Convert index to sequence from custom alphabet将索引从自定义字母转换为序列
【发布时间】:2014-09-28 10:42:44
【问题描述】:

我想生成一个函数,它接受一个整数 x 和 char 数组,并返回一个字符串 x 步入序列。

例如,考虑字母“abc”,它会产生字符串 a、b、c、aa、ab、ac、ba、bb、bc、ca、cb、cc、aaa、aab... 如果传入索引 0,我希望输出为“a”;同样,如果传入索引 34,我希望输出 'cbb'。

对于字母 '0123456789',我希望字符串 0、1、2、3、4、5、6、7、8、9、00、01、02、03、04、05、06、07、 08、09、10、11...

到目前为止,我已经写了以下内容,但是在行为偏离的案例 21-23、33-35、45-47 上遇到了问题,我已经盯着这个问题看了好几个小时,没有出现模式跳跃在我身上(关于字母大小和索引)。起初我没有注意到这个问题,使用更大的字母,直到它在我的程序中进一步产生更大的问题。

我不会假装下面的代码很优雅,遵循良好的实践,也没有经过优化——在这个阶段,我真的只是想了解这种模式的正确实现,并且一直在改变一切尝试解决问题。如果变量名称令人困惑,请提前道歉。另外,这是一个常见的模式/问题吗?我试图搜索类似的算法,但无法找到任何与我想到的术语有关的东西。

unsigned long power(int num, int exp)
{
    int i;
    unsigned long ret = num;

    if (exp == 0) return 1;

    for (i = 1; i < exp; i++)
    {
        ret *= num;
    }

    return ret;
}

unsigned long sumsqr(int base, int exp)
{
    unsigned long sum;

    for (sum = 0; exp > 0; exp--)
    {
        sum += power(base, exp);
    }

    return sum;
}

char * generateStringT(unsigned long index, char * charmap)
{
    unsigned long scaler;
    unsigned long remainder;
    unsigned long divisor;
    int base;
    int exponent;
    int factor;  
    char * buffer;
    char * string;
    int i;

    buffer = malloc(sizeof(char) * 100);
    i = 0;

    base = strlen(charmap);

    exponent = 0;
    divisor = 0;
    remainder = index;

    while(sumsqr(base, exponent) <= index)
    {
        exponent++;
    }
    exponent--;

    factor = exponent;

    while(factor >= 0)
    {
        divisor = power(base, factor);
        if ((factor > 1) && (exponent > 0))
        divisor += power(base, factor-1);

        scaler = remainder/divisor;

        remainder = remainder - scaler * divisor;
        printf("%lu,", scaler);

        if ((factor == exponent) && (exponent > 0)) scaler--;
        buffer[i++] = charmap[scaler];

        factor--;
    }


    buffer[i++] = '\0';

    string = malloc((strlen(buffer) + 1) * sizeof(char));
    strcpy(string, buffer);
    free(buffer);

    return string;
}

【问题讨论】:

  • ".. 这是常见的模式/问题吗?"是的:使用a,b,c 的页码通常遵循这种模式(例如,在 PDF 中使用时)。
  • @Jongware 好点!这让我找到了一些有用的东西 - 谢谢! codereview.stackexchange.com/questions/13105/…

标签: c algorithm


【解决方案1】:

您在那里尝试执行的操作看起来像是基本转换,但实际上略有不同。任何基数中的任何数字都可以被认为在表示的数字后面有无限多个前面的零(或该基数的最低有效数字)。这不是你的情况。

在您的情况下,您重视所代表数字的位数,这使得索引它们稍微复杂一些。使用数学中的基数,可以很容易地计算任何基数b 中表示的数字的索引;也就是说,rank 的总和乘以 base 的每个数字的 order 的幂。在您的情况下,索引会建立一个额外的sum_{k = 1}^{amount.of.digits.on.our.number - 1} base^k。如果我们从索引中减去那个加法,我们的任务就变得相当容易了。

可以使用您的 sumsqr 函数计算该加法。

在这里,我稍微更改了您的代码,在我进行更改的地方使用 cmets,这可以解决很多问题,就像您期望的那样:

// added this
remainder -= sumsqr(base, exponent);

while (factor >= 0)
{
    divisor = power(base, factor);

    // commented this out
    // if ((factor > 1) && (exponent > 0))
    //  divisor += power(base, factor - 1);

    scaler = remainder/divisor;

    remainder = remainder - scaler * divisor;
    printf("%lu,", scaler);

    // commented this out
    // if ((factor == exponent) && (exponent > 0))
    //  scaler--;

    buffer[i++] = charmap[scaler];

    factor--;
}

我不确定你想对我注释掉的部分做什么。我的猜测是,您试图将divisor 增加我之前谈到的差异量,而不是减少indexremainder 的量。

希望这对您有所帮助。

【讨论】:

    【解决方案2】:

    不是修复(乍一看,您的代码使用了类似的想法——但更复杂!),但这是我用来将整数索引转换为 a,b,c 格式页码的代码:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    char *number_alpha (char *dest, int value, char *base)
    {
        char *ddest = dest, *startdest = dest, swop;
    
        if (value < 0)
        {
            value = -value;
            *dest = '-';
            startdest++;
            ddest++;
        }
        value++;
        do
        {
            *ddest = base[((value-1) % strlen(base))];
            ddest++;
            value = (value-1)/strlen(base);
        } while (value > 0);
        *ddest = 0;
        ddest--;
        while (ddest > startdest)
        {
            swop = *ddest;
            *ddest = *startdest;
            *startdest = swop;
            startdest++;
            ddest--;
        }
        return dest;
    }
    
    int main (int argc, char **argv)
    {
        int number;
        char result[256];
    
        if (argc != 3)
        {
            printf ("usage: [number] [string]\n");
            return -1;
        }
    
        number = strtol (argv[1], NULL, 10);
        number_alpha (result, number, argv[2]);
        printf ("%d in 'base' %s yields %s\n", number, argv[2], result);
    
        return 0;
    }
    

    非常类似于常见的任务“将整数转换为十进制表示法”。通过删除value++ 并将(value-1) 两次更改为number_alpha 中的value,您将获得一个沼泽标准的Int-To-Ascii 例程。这个很特别,因为“换行”出现在不同的地方:对于0123456789 的基数,递增9 显示00,而不是10

    示例输出:

    0 in 'base' abc yields a
    34 in 'base' abc yields cbb
    34 in 'base' 0123456789 yields 24
    -34 in 'base' abc yields -cbb
    9 in 'base' 0123456789 yields 9
    10 in 'base' 0123456789 yields 00
    

    --

    请参阅Translate a column index into an Excel Column Name 了解其他语言的一些实现。他们似乎专注于递归解决方案,而我的解决方案是线性的(无论好坏)。

    【讨论】:

    • 感谢您的回答!用我的函数包装你的解决方案似乎完全没有任何变化。我非常感谢您的贡献,现在我应该从您的解决方案中获得足够的指导来分析我的算法并改进它。再次感谢!
    猜你喜欢
    • 2014-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-04
    相关资源
    最近更新 更多