例如我用递归求一个解,当求到解时我想直接跳到主函数结束程序,怎么做? 可以用什么方法及详细使用方法?谢谢
int
haveSolution
=
0
;
void
proc()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
if (得到可行解)
haveSolution = 1;
//跳到main函数注释行
else
//递归调用
proc();
return;
}
void
main()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
proc();
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if (haveSolution) /**//*跳到这里 */
cout << "got the solution";
else
cout << "not";
return;
}
iamcaicainiao(老菜,长征)
int
haveSolution
=
0
;
#include
<
iostream.h
>
int
proc()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if (1)...{//得到可行解
haveSolution = 1;
return 1;
//跳到main函数注释行
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
//递归调用
proc();
return 0;
}
return 2;
}
void
main()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
int i = proc();
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if (i==1)...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if (haveSolution) /**//*跳到这里 */
cout << "got the solution";
else
cout << "not";
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
}else if(i==2)...{
……
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
}else if(i==0)...{
……
}else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
……
}
return;
}
caijize(砂子)
楼主的思路不是很好,要直接跳出就不要用递归, 要用递归就得一个个地跳回去,否则就会造成内存泄漏。
建议楼主再仔细地看看递归的使用方法和使用条件。
按照楼主的意思,应该这样实现:
int
haveSolution
=
0
;
void
proc()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**/////
//求解
……
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//
if (得到可行解)
haveSolution = 1;
else
//递归调用
proc();
return;
}
void
main()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
proc();
if (haveSolution)
cout << "got the solution";
else
cout << "not";
return;
}
pagechen(天外飞来的仙)
我想longjmp 和 setjmp 两个函数可以帮助你。
不过如果不理解内涵,比较难用
alvachien(白衣战神,四大绝技:C#/C++/T-SQL/ABAP)
简单,直接跳使用throw一个exception就出来了。
完全可以通过throw一个特定的类型来达到直接跳出的效果。
vc_hunter(飞天御箭)
可以用内嵌汇编的方式修改ebp或esp,这方法虽然可用,但会使程序变得很难看懂。而且,不对WIN32汇编有一定了解,实现起来不是很容易
/**/
/*实现了深度递归加跳出,或许该叫递推?*/
#include
"
stdafx.h
"
#include
"
windows.h
"
int
digui(
int
n,
int
value,
int
retadd)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
if(retadd==0)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
__asm
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
mov retadd,ebp //保存第一次进入时的返回地址
}
}
if(n==1)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
__asm //求得结果后直接返回main
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
mov eax,value
mov ebp,retadd
mov esp,ebp
pop ebp
ret
}
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
digui(n-1,value*2,retadd);
}
::Sleep(9999999999);
return 0;
}
void
main(
int
argc,
char
*
argv[])
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
int a=digui(5,2,0);//求2的5次方
printf("%d",a);
}
pankun(剑神一笑 Console下面干革命)
递归要一步步ret,不然堆栈不会平衡.用楼上改esp的方法当然也可以.
pagechen(天外飞来的仙)
longjmp 和 setjmp 就是C实现远程跳转的好方法,是对修改ebp方法的封装。
throw 好吗?假设你在第100层递规中药退出,你要throw多少层啊?浪费啊
ox_thedarkness()
厄,很有趣的问题。分别有 C、 C++ 两种方法可以解决你的问题。
C方法是:使用标准库<csetjmp>或者<setjmp.h>中的 setjmp 和 longjmp。注意,前面所谓 goto 的方法是错误的。 goto 不能完成函数间跳转。
C++方法简洁得多: 抛出异常;函数调用时则用 try ... catch 捕获异常。
下面给出C++方法的一个例子。
//
判断 n 是否奇数
//
结果由 throw 抛出,奇数抛出true,否则抛出false
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
void
isOdd( unsigned
int
n )
...
{
if( n == 0 ) throw false;
if( n == 1 ) throw true;
isOdd( n - 2 );
}
//
不过调用起来就有些麻烦:
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
int
main()
...
{
// 用法类似这样
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
try...{
isOdd( 21 );
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
}catch( bool odd )...{
cout<< ( odd? "odd" : "even" )<< endl;
}
}
一个问题是,上面三种方法都不是透明的。isOdd 不能像一般函数一样使用,而必须详细阅读和理解设计者的文档,正确使用晦涩的 __asm、 setjump 、try catch等等、否则会令程序崩溃。这不是好的设计。
一个解决方案是:给递归部分一个壳。使用两个函数,递归函数负责递归,壳函数负责这些复杂的调用过程,用户只调用壳函数。
为了避免用户调用递归函数,以及命名冲突问题,可以使用 nest function 技术。 C/C++本身不直接支持内嵌函数,但是我们可定义一个局部struct,把内嵌的函数定义为其static成员
//
若 n 是奇数,返回true, 否则返回 false
//
内嵌函数递归 + 通过异常机制实现
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
bool
isOdd( unsigned
int
n )
...
{
// 一个Nest struct, 用于定义一个 nest 函数
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
struct Nst ...{
// 递归计算n是否奇数,计算完成时throw bool
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
static void recurve( unsigned int n )...{
if( n == 0 ) throw false;
if( n == 1 ) throw true;
recurve( n - 2 );
}
};
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
try...{
Nst::recurve( n );
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
}catch( bool odd )...{
return odd;
}
}
Nst 是 isOdd 函数内部定义的结构,他的名字只在 isOdd 内可见。所以你可以在所有函数内一致使用 Nst 作为内嵌结构的名字,而不会出现任何冲突。
现在 isOdd 是一个正常函数,可以正常调用了:
int
main()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
cout<< ( isOdd( 32 )?"odd":"even" ) <<endl;
}
下面是C风格的实现:
-----------------------------------------------------
我们使用<setjmp.h>中 setjmp 和 longjmp的方法实现跳转。
注意,纯C中结构不能有成员函数,所以nest function 技巧行不通了。另外C不支持bool,所以我们返回int。当然 C++ 编译器可以继续支持混合程序的技巧。
为了符合C标准,我们将定义一个额外的函数,两个额外的静态全局变量。这些额外的标识符都使用长名称,并且加上static限定词 —— 以便避免对全局名字空间更大的污染。
另外, C99之前的C标准中,外部连接的标识符只有前六个字母有效 —— 所以若是不加static限定词,我们就给上面的三个标识符取长长的名字就有危险啦,譬如那个recurve_is_odd。(C99之前的标准中,内部连接的标识符前31个字母为有效字符)
//
is_odd函数的实现细节。
//
!不要直接调用recurve_is_odd函数、或者访问下面两个变量
static
jmp_buf jb_is_odd;
static
int
n_is_odd;
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
static
void
recurve_is_odd( unsigned
int
n )
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if( n == 0 ) ...{ n_is_odd = 0; longjmp( jb_is_odd, 1 ); }
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if( n == 1 ) ...{ n_is_odd = 1; longjmp( jb_is_odd, 1 ); }
recurve_is_odd( n - 2 );
}
//
若 n 是奇数,返回true, 否则返回 false
//
函数递归, 通过setjmp longjmp实现
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
int
is_odd( unsigned
int
n )
...
{
if( setjmp( jb_is_odd ) == 0 )
recurve_is_odd( n );
else
return n_is_odd;
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
int
main()
...
{
if( is_odd( 23 )) printf( "odd " );
else printf( "even " );
}