递归函数,用于计算数字中的位数

Recursive function to count the amount of digits in a number

本文关键字:数字 用于 计算 递归函数      更新时间:2023-10-16

有没有办法编写一个递归函数,该函数打印数字中的位数,以便:

-这是一个空洞功能

-"if"条件是if(num==0),返回

-"else"将调用递归。

我看到了 2 种不同类型的代码,其中一种是"if"条件具有递归调用,另一种是"返回"。但这不是我想要的。

我对递归很糟糕,并试图通过自己编码来理解它,但没有成功。

这是我的代码(我明白为什么它打印 122 而不是 3,但我真的不知道编码有何不同。帮助任何人?

#include <iostream>
#include <string.h>
using namespace std;
void numOfDigits(unsigned int num);
int main(){
int num = 994;
numOfDigits(num);
}
void numOfDigits(unsigned int num)
{
int size = 1;
if (num==0)
return;
else
{
if (num / 10 != 0)
size++;
numOfDigits(num / 10);
}
cout << size;
}

使此代码正常工作的一个快速技巧是使size静态的,即更改

int size = 1;

static int size = 1;

但这仅在您第一次调用函数时有效。

对于更可靠的解决方案,在对函数的每次调用中,您必须传递到目前为止的计数:

void numOfDigits(unsigned int num, int countSoFar = 0) {
if (num == 0)
std::cout << countSoFar << 'n';
else
numOfDigits(num / 10, countSoFar + 1);
}

numOfDigits() 函数中有许多错误。

  1. 首先,每次调用函数时,都要声明一个名为 size 的新局部变量。这与调用函数中定义的"大小"无关。要查看此信息,请在初始化后打印大小。要解决此问题,请将大小设置为静态;然后,每次调用函数时,它将使用相同的静态变量。
  2. 当您在函数
  3. 末尾打印大小时,它只是在运行该函数后给出大小变量的值。即使将大小设置为静态,您也将打印大小的中间值。解决此问题的一种简单方法是允许函数返回大小,并且您只需在 main 函数中打印函数的值。

    #include <iostream>
    #include <string.h>
    using namespace std;
    int numOfDigits(unsigned int num);
    int main(){
    int num = 994;
    cout<<numOfDigits(num);
    }
    int numOfDigits(unsigned int num)
    {
    static int size = 1;
    if (num==0)
    return 0;
    else
    {
    if (num / 10 != 0)
    size++;
    numOfDigits(num / 10);
    }
    return size ;
    }
    

确保根据需要输入 (num == 0) 的大小写;在这种情况下,它会打印 0 作为答案。

PS:打印数字后始终加空格。否则,您可能会认为 1 2 2(实际打印的数字)是数字 122。

你可以通过引用传递一个值并使用它,每次调用这个函数时初始化ans=0

void recursive(unsigned int num,int &ans){
if(num == 0){
return;
}
else{
ans++;
recursive(num/10,ans);
}
}

看到这个和这个

不使用任何全局变量,此代码即可工作。只是一点说明:您声明了无符号的 int 参数,但您给函数的数字是一个有符号整数。

#include <iostream>
#include <string.h>
using namespace std;
void numOfDigits(unsigned int num, unsigned int& digits);
int main(){
unsigned int num = 93934;
unsigned int digits = 1;
numOfDigits(num, digits);
cout <<digits <<endl;
return 0;
}
void numOfDigits(unsigned int num, unsigned int& digits) {
if (num==0){
return;
}else{
if (num / 10 != 0){
++digits;
numOfDigits(num / 10, digits);
}
}
}

尝试全局声明大小,因为每次执行函数时都会初始化大小

int size = 1;
void numOfDigits(unsigned int num)
{
if (num==0)
return;
else
{
if (num / 10 != 0)
size++;
numOfDigits(num / 10);
}
}

主内尺寸的打印值

#include <iostream>
#include <string.h>
using namespace std;
void numOfDigits(unsigned int num);
void main(){
int num = 994;
int size = 1;
cout << numOfDigits(num, size);
}
void numOfDigits(unsigned int num, int &size)
{
if (num==0)
cout<<size;
else
{
if (num / 10 != 0)
size++;
numOfDigits(num / 10, size);
}
}

我认为您的误解是您认为size是一个变量。但是,在函数的每次调用中,您都有一个不同的函数。此外,函数的每次调用都会再次打印它。

cout不执行任何操作,因为它打印了一个没有内容的空白。

通常,你会给它一个返回参数,即累积的数字,比如

int numOfDigits(unsigned int num);
void main(){
cout << numOfDigits(994) << endl;
}

如果您出于某种原因不希望这样做,您可以通过引用来完成:

int numOfDigits(unsigned int num, unsigned int& digits);
void main(){
unsigned int digits;
numOfDigits(994,digits);
cout << digits << endl;
}

但这并不那么好。

也就是说,就风格而言,我要做的是让它成为一个循环(想法是你想避免大多数时候递归):

unsigned int numOfDigits(unsigned int num){
if(num == 0) { return 1; }
unsigned int size = 0;
while(num != 0){
size++;
num /= 10;
}
return size;
}

这也可以通过引用返回值的调用来完成。但同样,如果没有必要,这有点奇怪。

您甚至可以通过使用数学、cout << floor(log_10(num)) << endl;(如果 num 为零,则不考虑特殊情况)使其成为单行代码

一种可行的解决方案是将大小作为全局变量。但是,我建议不要这样做。一般应避免使用全局变量。只是想提一下,如果别人推荐的话。

最后,你可以使用一个类,比如DigitsCounter,它通常是短暂的,并且对方法进行递归调用,大小变量是一个类成员。不过,这对您来说太过分了。

试试这段代码:

int numOfDigits(unsigned int num)
{
int size = 1;
if (num!=0)
{
if (num / 10 != 0)
size+= numOfDigits(num / 10);
}
return size;
}

在主函数中使用返回值

在递归函数上使用void返回类型的问题是,嵌套调用不可能将任何信息返回到调用它们的方法。如果我们想在第一次(外部)调用时打印值,则第一次调用无法从其递归调用中获取任何信息。

正如你所观察到的,不可能简单地打印值,因为从递归调用到输出字符没有一对一的映射(如果我们使用基数 10......请参阅附录)。如果我们放宽if条件必须立即返回的条件,我们可以通过将信息作为参数传递给递归调用,然后在递归的最深层次打印值来避免这个问题。例如:

// The accumulator starts at 0, then increases by 1 for each recursive call
void numOfDigits(unsigned int num, unsigned int accumulator = 0) {
if (num == 0) {
if (accumulator == 0) cout << 1; // Special case: numOfDigits(0) = 1
else cout << accumulator;
} else numOfDigits(num / 10, accumulator + 1);
} 

旁注:这现在是一种尾递归方法:它将递归调用作为其最后一个操作。这很有用,因为它允许编译器降低方法的空间复杂性(请参阅说明)。实质上,编译器将方法转换为简单迭代,无需累积堆栈帧。

附录:我可以看到保留约束 (2) 的唯一方法是打印基数 1 中的位数,因为从参数中获取的每个数字都直接对应于基数 1 中的单个字符)。这可能不是你的意思,但这里有一个解决方案:

// The accumulator starts at 0, then increases by 1 for each recursive call
void numOfDigits(unsigned int num) {
if (num == 0) return;
else {
cout << 1
numOfDigits(num / 10);
}
}

:注:此方法不会为numOfDigits(0)打印任何内容,如果我们想保持行if (num == 0) return;,这是必需

  • numOfDigits 是一个 void 函数

  • "if"条件是if(num==0),返回

  • "else"将调用递归。

这里:

void numOfDigits(unsigned int num)  {
if (num == 0)
return;
// The "else" will call the recursion.
else {
static int size = 1;
if (num / 10 != 0) {
size++;
numOfDigits(num / 10);
}
else {
cout << size << 'n';
size = 1;
}
}
}