我正在学习递归,所以我试图创建一个程序,以递归方式反转数组并使用分而治之的技术(我不确定这是否分而治之? ),所以我的问题是,我想知道为什么如果我删除第11行程序仍然正常工作,但如果我删除第16行,它将无限进行。
我检查了我的调试器,我知道为什么它是无限循环,因为每个堆叠的帧索引仍然小于正确,这使得循环无限循环,所以我的问题,为什么递归调用从检查while条件开始并跳过第11行?这对我来说很奇怪,因为我只是学习了一些递归的基础知识,所以这对我来说很容易让人困惑。所以在我的代码中,第16行被认为是基本情况?因为我从教程中学到了递归需要一个基本案例。
#include <stdio.h>
#define size 10
void swap(int *a, int *b)
{
int temp= *b;
*b = *a;
*a = temp;
}
void revcur (int arr[], int left, int right)
{
if (left>=right) return; //This program still works even if i delete this line or comment
while (left<right)
{
swap(&arr[left],&arr[right]);
revcur(arr,left+1,right-1);
return; //This program will go to infinite recursive if i delete this
}
}
int main()
{
int arr[size]={1,2,3,4,5,6,7,8,9,10};
revcur(arr,0,size-1);
int i; for (i=0; i<size; i++)
{
printf("%d ",arr[i]);
}
}
答案 0 :(得分:2)
假设left = 2且right = 1。如果你离开第11行会发生什么,条件为真,你将立即退出函数(return)。当你删除第11行时,你将进入while循环。 while语句检查left是否小于右边,而不是右边。因此,它会跳过while循环中的所有代码,这些代码会将您带到函数的末尾,因此它将自动返回。这与将第11行留在原位的情况相同。
当你删除第16行时它无限循环的原因是因为你没有更新&#34; left&#34;和&#34;对&#34;一个新的价值。因此,如果左边确实小于正确,它将进入循环,因为左和右的值永远不会改变,下一次它到达&#34;而#34;声明,&#34;左&#34;仍将低于&#34;对&#34;因此循环将无限期地继续。
答案 1 :(得分:2)
此代码模式:
while (condition)
{
// do something
return;
}
完全等同于
if (condition)
{
// do something
return;
}
换句话说,您的基本案例是!condition
。
您可以用
替换您的实现void revcur(int arr[], int left, int right)
{
if (left>=right) return;
swap(&arr[left],&arr[right]);
revcur(arr,left+1,right-1);
}
这将完全等效(while
从未实际循环)。
您的版本似乎有迭代等效的痕迹:
void revcur(int arr[], int left, int right)
{
while (left<right) {
swap(&arr[left++],&arr[right--]);
}
}
答案 2 :(得分:1)
你的功能过于复杂,实际上只是这样做:
void revcur(int arr[], int left, int right)
{
if (left<right)
{
swap(&arr[left], &arr[right]);
revcur(arr, left + 1, right - 1);
}
}
原始函数中的while
循环永远不会循环多次,因此具有
while
实际上毫无意义;写if
只是一种奇怪的方式。
考虑以下功能。
void foo(int x)
{
printf("x = %d\n",x );
if (x > 0)
foo(x - 1);
}
void bar(int x)
{
printf("x = %d\n", x);
while (x > 0)
{
bar(x - 1);
return;
}
}
foo
和bar
执行的操作完全相同,只是bar
正在滥用while
循环使用它作为if
,就像您在你的功能。
现在尝试从return
函数中删除bar
,看看会发生什么。
答案 3 :(得分:0)
你的功能是void
。所以你最后一次在递归中调用它。它不会进入while循环,因此它不会再次调用该函数,从而结束递归。因为ypu在你的while循环中有一个返回值,我猜你可以用if
语句替换它,它基本上会做同样的事情,你可以摆脱return
。
答案 4 :(得分:0)
本声明
if (left>=right) return; //This program still works even if i delete this line or comment
只是多余的。
如果left >= right
为真,则while语句left < right
的条件为false,并且不会执行while循环。
所以你可以删除if语句。
void revcur (int arr[], int left, int right)
{
while (left<right)
{
swap(&arr[left],&arr[right]);
revcur(arr,left+1,right-1);
return; //This program will go to infinite recursive if i delete this
}
}
但是你可能不会删除return语句,因为在这种情况下循环将是无限的,因为在循环内部变量left
和right
本身的值不会改变,并且如果最初计算结果为true,则while语句的条件将始终求值为true。
另一方面,使用while语句是没有意义的,因为在任何情况下都假定循环体只会因return语句而执行一次。 while语句的条件很重要。
所以你可以用while语句替换if语句。
例如
void revcur (int arr[], int left, int right)
{
if ( left < right)
{
swap(&arr[left],&arr[right]);
revcur(arr,left+1,right-1);
}
}
考虑到如果数组只包含一个元素,那么它将与自身交换,该函数将有一个冗余的递归调用。
该函数可以重写为只有两个参数,并且没有冗余的递归调用。
下面是一个演示程序,演示如何使用两个参数编写函数。
#include <stdio.h>
void swap( int *a, int *b )
{
int temp= *b;
*b = *a;
*a = temp;
}
void reverse( int a[], size_t n )
{
if ( !( n < 2 ) )
{
swap( &a[0], &a[n-1] );
reverse( a + 1, n - 2 );
}
}
int main(void)
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const size_t N = sizeof( a ) / sizeof( *a );
for ( size_t i = 0; i < N; i++) printf( "%d ", a[i] );
putchar( '\n' );
reverse( a, N );
for ( size_t i = 0; i < N; i++) printf( "%d ", a[i] );
putchar( '\n' );
return 0;
}
程序输出
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1