Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
这个递归C代码是如何工作的?_C_Recursion - Fatal编程技术网

这个递归C代码是如何工作的?

这个递归C代码是如何工作的?,c,recursion,C,Recursion,有很多递归问题,我基本上了解一些简单的递归算法,比如数组元素和。但是,我的朋友给了我一个代码,它反转了一个数组: void r(int a[], int s) { if(s <=2 ) return; int t = a[0]; a[0] = a[s-1]; a[s-1] = t; r(&a[1], s-2); // this line confused me, why &a[1] } void r(int a[],i

有很多递归问题,我基本上了解一些简单的递归算法,比如数组元素和。但是,我的朋友给了我一个代码,它反转了一个数组:

void r(int a[], int s)
{
     if(s <=2 ) return;
     int t = a[0];
     a[0] = a[s-1];
     a[s-1] = t;

     r(&a[1], s-2); //  this line confused me, why &a[1]
}
void r(int a[],int s)
{

如果(s需要了解的重要事情是
a
是指向数组第一个元素的指针,那么
a
&a[0]
&a[1]
是指向数组第二个元素的指针。因此,如果使用
&a[1]调用函数
作为其参数,它作用于从第二个元素开始的子数组。

需要了解的重要一点是
a
是指向数组第一个元素的指针,因此
a
&a[0]
&a[1]相同
是指向数组第二个元素的指针。因此,如果以
&a[1]
作为参数调用函数,它将在以第二个元素开头的子数组上工作。

&a[1]
相当于
a+1
,即指向数组第二个元素的指针。函数调用将反转“中间”数组的
s-2
元素。

&a[1]
相当于
a+1
,即指向数组第二个元素的指针。函数调用反转数组的“中间”
s-2
元素。

它与

void r(int *arr, size_t len)
{
     for ( ; len >= 2; arr+=1,len-=2 ) {
       int t = arr[0];
       arr[0] = arr[len-1];
       arr[len-1] = t;
       }

}
,其中递归调用被循环替换。循环的“增量”部分(
arr+=1,len-=2
)与递归调用的参数完全相同;结束条件(
len>=2
)等同于递归停止符(这在原始中是错误的)。

它与

void r(int *arr, size_t len)
{
     for ( ; len >= 2; arr+=1,len-=2 ) {
       int t = arr[0];
       arr[0] = arr[len-1];
       arr[len-1] = t;
       }

}

,其中递归调用被循环替换。循环的“增量”部分(
arr+=1,len-=2
)与递归调用的参数完全相同;结束条件(
len>=2
)相当于递归停止符(在原始情况下是错误的)。

必须使用以下参数调用函数:

  • 指向数组第一个元素的指针。在C语言中,可以使用数组的名称来引用它
  • 数组的大小
第一个“if”检查数组是否至少有两个元素。接下来,函数要做的是交换数组中第一个和最后一个元素的位置


递归调用更改下一步必须执行的边界。它将数组的开头增加一个位置,并将数组的结尾减少一个位置;因为这两个元素在此迭代中已反转。

必须使用以下方法调用函数:

  • 指向数组第一个元素的指针。在C语言中,可以使用数组的名称来引用它
  • 数组的大小
第一个“if”检查数组是否至少有两个元素。接下来,函数要做的是交换数组中第一个和最后一个元素的位置


递归调用改变了下一步必须执行的边界。它将数组的开头增加一个位置,同时也将数组的结尾减少一个位置;因为这两个元素在这个迭代中被颠倒了。

此算法背后的思想是在每一步:

-:要交换数组的最后一个
a[s-1]
和第一个
a[0]
元素,请执行以下操作:

    int t = a[0];
    a[0] = a[s-1];
    a[s-1] = t;
-:和以递归方式交换中间位置:

    r(&a[1], s-2);
要理解语法,请记住
&a[n]
是给定数组的
n+1
第个元素的地址。如果有
int*b=&a[1]
,则
b[0]==a[1]
b[1]==a[2]
,等等

因此:

  • &a[1]
    指从数组
    a
    的第二个元素开始的数组
  • s-2
    意味着递归传递的数组长度缩短了2个元素
如果您有一个数组
[1 2 3 4 5 6 7 8 9 10]
,下面是递归过程中发生的情况:

[1 2 3 4 5 6 7 8 9 10] // r(&a[0], 10)
10 [2 3 4 5 6 7 8 9] 1 //   r(&a[1], 8
10 9 [3 4 5 6 7 8] 2 1 //     r(&(&a[1])[1], 6)
10 9 8 [4 5 6 7] 3 2 1 //       r(&(&(&a[1])[1])[1], 4)
10 9 8 7 [5 6] 4 3 2 1 //         r(&(&(&(&a[1])[1])[1])[1], 2)

很酷的是,该分析向我们展示了终止条件
s该算法背后的思想是在每一步:

-:要交换数组的最后一个
a[s-1]
和第一个
a[0]
元素,请执行以下操作:

    int t = a[0];
    a[0] = a[s-1];
    a[s-1] = t;
-:和以递归方式交换中间位置:

    r(&a[1], s-2);
要理解语法,请记住
&a[n]
是给定数组的
n+1
第个元素的地址。如果有
int*b=&a[1]
,则
b[0]==a[1]
b[1]==a[2]
,等等

因此:

  • &a[1]
    指从数组
    a
    的第二个元素开始的数组
  • s-2
    意味着递归传递的数组长度缩短了2个元素
如果您有一个数组
[1 2 3 4 5 6 7 8 9 10]
,下面是递归过程中发生的情况:

[1 2 3 4 5 6 7 8 9 10] // r(&a[0], 10)
10 [2 3 4 5 6 7 8 9] 1 //   r(&a[1], 8
10 9 [3 4 5 6 7 8] 2 1 //     r(&(&a[1])[1], 6)
10 9 8 [4 5 6 7] 3 2 1 //       r(&(&(&a[1])[1])[1], 4)
10 9 8 7 [5 6] 4 3 2 1 //         r(&(&(&(&a[1])[1])[1])[1], 2)
酷的是,这个分析告诉我们终止条件
s简化了疯狂行走槽

void reverse(int a[], int s)
{
    int temp;              /* temporary value */

    if (s <= 2) return;    /* trigger done */

    t        = a[0];       /* temp = first index of a */
    a[0]     = a[s - 1];   /* a[0] = a[end - 1] (end including \0) */
    a[s - 1] = t;          /* a[end - 1] = temp */

    r(&a[1], s - 2);       /* pass address of a[1] and end - 2 */
}
我们得到;
main()
调用
reverse(ABCDEFG,7)

清单1

  • A
    的地址引用被推送到堆栈(A{BCDEFG})
  • 7被推到堆栈上
  • 调用方的返回地址被推送到堆栈上
  • 等等
  • 调用的函数
什么的

#::::::::::::::::::::::::::::::::::::::::::::::::::::

reverse(ABCDEFG, 7); # Push to STACK 0xB (As List 1)
#====================================================
789abcd <- Memory address.
ABCDEFG <- Values.
0123456 <- Indexes for a in recursion 1.

if (7 <= 2) return;
temp = A
               +     .
a[0] = a[6] => ABCDEFG = GBCDEFG
                     +
a[6] = temp => GBCDEFG = GBCDEFA
简化疯狂行走槽

void reverse(int a[], int s)
{
    int temp;              /* temporary value */

    if (s <= 2) return;    /* trigger done */

    t        = a[0];       /* temp = first index of a */
    a[0]     = a[s - 1];   /* a[0] = a[end - 1] (end including \0) */
    a[s - 1] = t;          /* a[end - 1] = temp */

    r(&a[1], s - 2);       /* pass address of a[1] and end - 2 */
}
我们得到;
main()
调用
reverse(ABCDEFG,7)

清单1

  • A
    的地址引用被推送到堆栈(A{BCDEFG})
  • 7被推到堆栈上
  • 调用方的返回地址被推送到堆栈上
  • 等等
  • 调用的函数
什么的

#::::::::::::::::::::::::::::::::::::::::::::::::::::

reverse(ABCDEFG, 7); # Push to STACK 0xB (As List 1)
#====================================================
789abcd <- Memory address.
ABCDEFG <- Values.
0123456 <- Indexes for a in recursion 1.

if (7 <= 2) return;
temp = A
               +     .
a[0] = a[6] => ABCDEFG = GBCDEFG
                     +
a[6] = temp => GBCDEFG = GBCDEFA

如果(s@wildplasser)你是绝对正确的,请参阅下面我的答案中的分析。如果(s@wildplasser)你是绝对正确的,请参阅下面我的答案中的分析。