如何在递归函数

时间:2015-07-04 22:01:44

标签: java c arrays pointers recursion

我有一个递归函数,我将数组作为局部变量传递。 (我知道如果你在一个函数中传递一个数组作为参数,只有指针,即数组的起始地址被传递。但我的目标是找到一种方法来克服所有这些限制,以便在一个纯粹的应用程序点工作视图。)

在每个递归级别,我正在改变数组的内容并使用此数组调用递归函数。我想要的是,当递归结束时,我希望每个级别的数组都像在递归中前进一样。目前我观察到的是,在返回递归时,所有调用中的数组内容保持不变。

这是我的代码

#include <stdio.h>

int len = 0;

int main(void)
{
 int a[5] = {0};

 len = sizeof(a)/sizeof(*a);

 fun(a,0);

 return 0;
}

int fun(int a[], int j)
{
 if(j==5)
  return;

 a[j] = j;
 fun(a,j+1);
}

这是我的gdb跟踪的输出。正如您所看到的,在前进过程中,数组内容看起来像

level 0 -{0}
level 1 -{0,1}
level 2 -{0,1,2}
level 3 -{0,1,2,3}
level 4 -{0,1,2,3,4}

但回来后,它总是

level 4 -{0,1,2,3,4}
level 3 -{0,1,2,3,4}
level 2 -{0,1,2,3,4}
level 1 -{0,1,2,3,4}

我希望我的数组在返回递归时看起来像这样

level 4 -{0,1,2,3,4}
level 3 -{0,1,2,3}
level 2 -{0,1,2}
level 1 -{0,1}
level 0 -{0}

gdb trace

(gdb) disp *a@5
1: *a@5 = {0, 0, 0, 0, 0}
(gdb) disp j
2: j = 0
(gdb) s
2: j = 0
1: *a@5 = {0, 0, 0, 0, 0}
2: j = 0
1: *a@5 = {0, 0, 0, 0, 0}
fun (a=0x7fffffffdf90, j=1) at main.c:18
2: j = 1
1: *a@5 = {0, 0, 0, 0, 0}
2: j = 1
1: *a@5 = {0, 0, 0, 0, 0}
(gdb) s
2: j = 1
1: *a@5 = {0, 0, 0, 0, 0}
2: j = 1
1: *a@5 = {0, 1, 0, 0, 0}
fun (a=0x7fffffffdf90, j=2) at main.c:18
2: j = 2
1: *a@5 = {0, 1, 0, 0, 0}
2: j = 2
1: *a@5 = {0, 1, 0, 0, 0}
2: j = 2
1: *a@5 = {0, 1, 0, 0, 0}
(gdb) s
2: j = 2
1: *a@5 = {0, 1, 2, 0, 0}
fun (a=0x7fffffffdf90, j=3) at main.c:18
2: j = 3
1: *a@5 = {0, 1, 2, 0, 0}
2: j = 3
1: *a@5 = {0, 1, 2, 0, 0}
2: j = 3
1: *a@5 = {0, 1, 2, 3, 0}
1: *a@5 = {0, 1, 2, 3, 0}
(gdb) s
fun (a=0x7fffffffdf90, j=4) at main.c:18
2: j = 4
1: *a@5 = {0, 1, 2, 3, 0}
2: j = 4
1: *a@5 = {0, 1, 2, 3, 0}
2: j = 4
1: *a@5 = {0, 1, 2, 3, 4}
fun (a=0x7fffffffdf90, j=5) at main.c:18
2: j = 5
1: *a@5 = {0, 1, 2, 3, 4}
1: *a@5 = {0, 1, 2, 3, 4}
(gdb) s
2: j = 5
1: *a@5 = {0, 1, 2, 3, 4}
2: j = 5
1: *a@5 = {0, 1, 2, 3, 4}
2: j = 4
1: *a@5 = {0, 1, 2, 3, 4}
2: j = 3
1: *a@5 = {0, 1, 2, 3, 4}
2: j = 2
1: *a@5 = {0, 1, 2, 3, 4}
(gdb) s
2: j = 1
1: *a@5 = {0, 1, 2, 3, 4}
2: j = 0
1: *a@5 = {0, 1, 2, 3, 4}
main () at main.c:13

编辑:  此外,这是其他语言的情况,例如java。我认为在java中指针的概念不存在,它将每个数组保存为单独的递归调用的局部变量。但我得到的输出与C相同。

代码

class Hello
{
 public static void main(String[] args)
 {
  int[] a = {0,0,0,0,0};
  fun(a,0);

  System.out.println("");
 }

 static void fun(int[] a, int j)
 {
  int i = 0;

  if(j==5)
  {
   for(i=0;i<5;i++)
    System.out.print(a[i]);

   System.out.println("");
   return;
  }

  a[j] = j;
  fun(a,j+1);

  System.out.print("at j=="+j+" : ");
  for(i=0;i<5;i++)
   System.out.print(a[i]);

  System.out.println("");
 }
}

输出

01234
at j==4 : 01234
at j==3 : 01234
at j==2 : 01234
at j==1 : 01234
at j==0 : 01234

4 个答案:

答案 0 :(得分:1)

在返回之前,只需恢复每次通话的内容:

void fun(int a[], int j) {
    if (j == 5) {
        return;
    }

    int tmp = a[j];
    a[j] = j;
    fun(a, j+1);
    a[j] = tmp;
}

同样如评论中所述,您不应在未事先声明或定义的情况下使用函数。您可以在main()之前使用原型声明它:

void fun(int a[], int j);

或者只是在main()之前完全定义它并且您不会需要原型。

注意:该函数不会返回任何内容,因此正确的返回类型为void,而不是int

答案 1 :(得分:0)

  

我想要的是,当递归结束时,我希望数组在   每个级别都像在递归中前进一样。

可以通过struct包装数组来将其视为值类型。

E.g

#include <stdio.h>

int len = 0;

typedef struct  {
    int a[5];
} varType;

void fun(varType v, int i);

int main(void){
    varType v = {0};
    len = sizeof(v.a)/sizeof(*v.a);

    fun(v,0);

    return 0;
}

void fun(varType x, int j){
#if DEBUG
    for(int i=0; i < len; ++i)
        printf("%d ", x.a[i]);
    printf("\n");
#endif
    if(j==5)
        return;

    x.a[j] = j;
    fun(x, j+1);
#if DEBUG
    for(int i=0; i < len; ++i)
        printf("%d ", x.a[i]);
    printf("\n");
#endif

}

答案 2 :(得分:0)

//something of the form to null out the last element prior to falling out of each recursion

int fun(int a[], int j)
{
    static int i = 0;

    if(j<5){
        a[j] = j;
        i++;//inc on each recursion

        fun(a,j+1);
    }

    i--;//decrement on  falling out of each recursion

    a[i] = 0;//null out the last index

    return 0;
}

答案 3 :(得分:0)

正如其他人所暗示的那样,在大多数情况下,重用相同的数组更为方便和有效(就像你在传递引用时已经做的那样),而是让堆栈的每个级别“撤消”无论它在返回之前对数组做了什么。这将导致您需要的输出(当每个级别的递归调用完成时,每个级别都将数组视为未更改。)

但是,由于您明确询问如何在每个级别创建一个新数组,以下是您在Java中如何做到这一点:

只需将递归调用更改为fun(a, j + 1);fun(Arrays.copyOf(a, a.length), j + 1);

如果您的问题只是如何复制数组(或任何对象),那么此处的递归实际上并不相关。我在我的C库上生锈了,但是必须有一种简单的方法来复制数组,或者你可以在几行中编写自己的复制方法,只需分配一个与源副本大小相同的新数组,然后逐个复制元素。