有没有办法将 int 赋入具有递归函数的字符串中,而无需将数字反转两次

Is there a way to assign an int into a string with a recursive function without reversing the number twice?

本文关键字:数字 两次 int 字符串 递归函数 有没有      更新时间:2023-10-16

有没有办法将 int 赋入具有递归函数的字符串中,而无需在每次递归调用时反转两次数字?

#include <string.h>
#include <iostream>
using namespace std;
int numreverse(long int n, long int rev);
void numtostring(unsigned int n, char str[]);
int main()
{
    char n[5];
    numtostring(1234, n);
    cout << n << endl;
}
void numtostring(unsigned int n, char str[]){
    n = numreverse(n, 0);//reverse the int
    if (n <= 0)return;
    else{
        str[0] = (char)(n % 10 + (int)'0');
        str[1] = 0;
        n /= 10;
        n = numreverse(n, 0);//reverse it again before recursive call
        numtostring(n, str + 1);
    }
}
int numreverse(long int n, long int rev){
    if (n == 0)
        return rev;
    return numreverse(n / 10, rev * 10 + n % 10);
}

注意:numtostring本身必须是递归的,并且不能修改其签名。

注意 2:不能使用其他库。

注3:应避免使用静态或全局变量。

numtostring()

接口是一个类似 C 的接口。 除了在问题中显示的main()测试程序中选择I/O操作之外,代码很可能是C而不是C++。

不将接口更改为numtostring()并且递归的要求使其比应有的更混乱和效率更低,如果您不被允许使用其他库函数,则更是如此。 在C++中,你真的不应该乱搞char等的原始数组。 但是,规则就是规则。 代码可以在没有 numreverse() 函数的情况下实现——当用于重新反转以一个或多个零结尾的数字时,该函数会失败(例如,1000 反转是 1,但 1 反转仍然是 1,而不是 1000,或者 100、10 甚至 1,000,000,000?)。

递归的关键技巧是确保您已正确识别和处理基本情况,然后递归案例建立在基本案例之上。 在这里,基本情况需要为"当值小于 10 时",递归情况(值至少为 10)需要获取前导数字的字符串(对应于值除以 10),然后附加最后一个数字。

棘手的是,该函数不能假设任何关于str的事情,除了"指针指向可修改的内存"和"有足够的空间来容纳正在格式化的数字加上终端空值"时第一次调用它。 特别是,它不能假设str开头有一个空字节。 因此,基本情况必须确保字符串以 null 结尾;递归大小写必须附加到"已知以 null 结尾"字符串。 这意味着代码的运行速度比约束不那么严格的代码慢,因为递归大小写必须找到字符串的末尾以附加其数字。

#include <iostream>
#include <cstring>  // memset() - used in test code
using namespace std;
void numtostring(unsigned int n, char str[]);
int main()
{
    int v;
    while (cin >> v)
    {
        char n[32];
        memset(n, 'xA5', sizeof(n));
        numtostring(v, n);
        cout << v << " == [" << n << "]n";
    }
}
void numtostring(unsigned int n, char str[])
{
    if (n > 9)
    {
        numtostring(n / 10, str);
        while (*str != '')
            str++;
        *str++ = n % 10 + '0';
        *str = '';
    }
    else
    {
        *str++ = n % 10 + '0';
        *str = '';
    }
}

示例运行:

$ n2s < data.n2s
0 == [0]
1 == [1]
2 == [2]
3 == [3]
4 == [4]
5 == [5]
6 == [6]
7 == [7]
8 == [8]
9 == [9]
10 == [10]
11 == [11]
99 == [99]
100 == [100]
999 == [999]
1000 == [1000]
1001 == [1001]
1002 == [1002]
$

(程序源码在n2s.cpp中,被编译成程序n2s,要转换的数字存储在data.n2s中。方括号和memset()操作只需确保格式化功能正确设置数据。

代码审查有帮助

上面numtostring()有一个丑陋的重复,多想一想就知道它不仅丑陋而且没有必要。更简化的代码版本是:

void numtostring(unsigned int n, char str[])
{
    if (n > 9)
    {
        numtostring(n / 10, str);
        while (*str != '')
            str++;
    }
    *str++ = n % 10 + '0';
    *str = '';
}

while循环令人讨厌,但很有必要。

使用帮助程序函数

由于numreverse()是允许的,因此代码显然可以使用作为解决方案的一部分编写的函数,因此更有效的解决方案使用递归帮助程序函数,但此解决方案也违反了规则,因为numreverse()本身不再是递归的。

#include <iostream>
#include <cstring>  // memset() - used in test code
using namespace std;
void numtostring(unsigned int n, char str[]);
int main()
{
    int v;
    while (cin >> v)
    {
        char n[32];
        memset(n, 'xA5', sizeof(n));
        numtostring(v, n);
        cout << v << " == [" << n << "]n";
    }
}
static char *n2s_helper(unsigned int n, char *str)
{
    if (n > 9)
        str = n2s_helper(n / 10, str);
    *str = n % 10 + '0';
    return str + 1;
}
void numtostring(unsigned int n, char str[])
{
    str = n2s_helper(n, str);
    *str = '';
}

对于相同的输入,它产生相同的输出。 它更有效,因为它只将一个空字节写入结果字符串,并且因为它不需要在每次需要添加数字时都找到字符串的末尾。 当然,需要大量的转换才能发现性能的差异。

在这两种解决方案中,操作代码(numtostring()n2s_helper())都是有效的C函数,就像它们是有效的C++函数一样,它们的行为在两种语言中都是相同的。

注意:numtostring本身必须是递归的,并且不能修改其签名。

这是一个愚蠢的要求。我至少可以更改返回类型吗?使代码更简单:

char * numtostring(unsigned int n, char * str)
{
    if (n >= 10) str = numtostring(n / 10, str);
    *str = n % 10 + '0';
    *++str = 0;
    return str;
}

终于做到了!(编辑 - OP 编辑的问题,不使用静态和全局变量)

#include <iostream>
using namespace std;
void numtostring(unsigned int n, char str[]) //no change made to the functionn signature
{
    char* count = str;
    static int counter = 0; //static integer does the trick
    char temp = 0;
    if (n)
    {
        temp = n%10 + '0';
        numtostring(n/10, count);
    }
    *(count+counter) = temp;
    if (temp) count[++counter] = '';
    else counter = 0;
}
int main()
{
    char n[5] = "TECH";
    numtostring(12, n);
    cout << n << endl;
    numtostring(32, n);
    cout << n << endl;
}