将索引从自定义字母转换为序列

时间:2014-09-28 10:42:45

标签: c algorithm

我想生成一个函数,它接受一个整数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,03,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;
}

2 个答案:

答案 0 :(得分:2)

你在那里尝试做什么看起来像一个基本转换,但实际上略有不同。任何基数中的任何数字都可以被认为好像它们在所代表的数字后面具有无限多的前面的零(或者该基数处的最低有效数字)。在你的情况下不是这样。

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

可以使用sumsqr函数计算添加内容。

在这里,我稍微更改了您的代码,并在我已完成更改的位置发表评论,这可以解决许多问题,就像您期望的那样:

// 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减少一定数量。

希望这会有所帮助。

答案 1 :(得分:1)

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

#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)更改为value中的number_alpha两次,您将获得一个标准的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。他们似乎专注于递归解决方案,其中我的是线性的(无论好坏)。