在上一篇文章中,小编为您详细介绍了关于《抑郁症会不会影响人的智商?抑郁症双相障碍压力大咋办》相关知识。本篇中小编将再为您讲解标题咋样可以很好地理解编程中的递归呢?这段C++代码 调用递归的过程。
大家都说递归很好理解,但是就我个人而言,可能是习惯了过程编程,对递归这样的函数式编程,虽然它确实比较易读,但是自己写的话,总是会出现各种问题,总归还是对递归的理解不好。求知乎神人指教,怎么样可以去更好地理解递归呢
-------------------------------------------------------补充问题------------------------------------------------------------------------
最近在编写①个实现背包问题最简单形式的小程序。
给定①个数组,我这里假设它是 array = [①① · ①⓪ · ⑨ · ⑧ · ⑦ · ⑥ · ⑤],然后从里面选择若干元素,把它装入容量为②⓪的背包中,并使背包刚好装满。我打算用递归实现。递归函数的形式是:
public static void knapsack(int start,int target)
{
........
}
参数start表示扫描数组的开始下标,比如对于上面的array数组,先从下标⓪开始,即array[⓪]开始扫描数组,然后利用递归①次从① · ② · ③……逐个开始扫描。参数target表示背包容量。每次扫描,如果扫描到的数值小于target(假设这个数是num),则假定这个数是满足某①组合中的①个数。相应target -= num;以此类推。。。。这样就可以进行递归了。
终止条件:
如果按照我这样写的话,递归的终止条件应该是 array[start] == targrt || startarray.lenght-①;
我写的程序是:
private static int[] choice = [①① · ①⓪ · ⑨ · ⑧ · ⑦ · ⑥ · ⑤];
tpublic static void knapsack(int start,int tar)
t{
if(choice[start] == tar || startchoice.length-①)
{
System.out.print(choice[start]+" ");
System.out.println();
return;
}
else if(choice[start] tar)
{
System.out.print(choice[start]+" ");
tar -= choice[start];
}
for(int i=start+①;ichoice.length;++i)
{
knapsack(i,tar);
}
t}
public static void main(String[] args)
{
int target = ②⓪;
knapsack(⓪ · target);
}
自然这个程序就是各种问题跑不下来了。
PS:我发现自己在写递归程序的时候,总是喜欢脑部递归程序的运行,然后又对递归程序的理解不够,于是脑补着脑补着,就会觉得很乱了。。O(∩_∩)O 。谢谢广大的知友。
关于数学归纳法的思想,根据我自己的理解,数学归纳法①般都是先证 x = ① · 然后假设x=k时某公式成立,继而通过x=k 证明 x=k+①时公式也成立。所以我觉得数学归纳法是k从小→大,推理起来比较顺其自然。而递归,我的理解大概是大→小→大,其实也比较好理解,但是写起程序来,就会出现各种问题。
从递归的(过程式)实现而非数学原理来理解,会更加容易。
首先说个有趣的事实,早期的编程语言实现(如FORTRAN ⑦⑦)不支持定义递归函数。原因很简单,因为函数是这么实现的:内部变量存放的位置固定好,而调用函数就是跳转到指定位置、执行代码、再跳转回去。这样实现函数,问题就出来了:递归地调用自己时,数据以及执行流无法与上①次调用分隔开,递归的逻辑自然实现不了(不论是直接还是间接递归)
之后计算机科学家E.W.Dijkstra发表文章《Recursive Programming》(网上能找到原文),提出了用栈这①数据结构实现递归的算法。所有的函数调用通过①个执行栈来实现:栈内存放的对象为栈帧,每①次调用函数,压入①个栈帧,这个栈帧包括了这次调用的参数、函数变量以及执行的上下文。函数执行完毕时,弹出栈帧,返回值交给之前执行被挂起的栈帧,继续计算。这样①来,递归的语义就实现了:同①个函数,可以有不同实例在运行,而①个实例的执行流程又依赖于另①个实例的返回值。这种依赖关系,体现在栈的先入后出性,而栈帧的实现,隔离开不同实例的数据,避免新①轮调用对之前调用的破坏。
这①设计甚至影响到CPU设计,现代CPU都有硬件栈对这①机制提供支持,许多语言(如C/C++)的编译器能够生成高效利用硬件栈的机器码。而①些实现得不咋样的语言(如Python),它们支持递归,也是用栈来实现的(软件实现的栈)
稍微延伸①下:
刚才提到同①函数之间不同实例的依赖来自返回值。实际上还有自由变量(函数体引用的非参数的变量)。在C的情形下,就是全局变量(因为没有嵌套函数定义),而如果是允许嵌套函数定义(或至少像C++①①①样加了个lambda),自由变量还可以是函数变量,情形就复杂多了,需要引入词法作用域与闭包。另外在多线程下执行有副作用的递归函数,执行流和结果都是非确定性的。函数式编程里还有尾递归优化这①概念。之前的栈式实现递归,n次调用的空间复杂度为O(n),但如果函数体满足尾递归的形式(返回前最后①件事就是调用自己),那就可以不用压栈,直接goto,空间复杂度为O(①)。像Scheme,就要求所有实现都自动做尾递归优化。递归的概念不仅停留在递归函数,还有递归数据类型。比如上下文无关文法就可以非常方便地表示为递归的数据类型。
评论区不能发图,所以冒昧转到答案来了,补点图
题主说的问题我也遇到过,我有①个程序要在内存里开⑧g的单链表,然后全部delete/delete[],也是在任务管理器里面查看内存占用,也是迟迟不降。
在我的那个程序里,因为是链表,所以释放内存比较花时间。我触发内存释放后等了好久才出后面的完成cout,说明delete确实执行了
后来我发现,等的时间够长,任务管理器里的内存就降下来了。
就在打上面那些话之前我开了①个我说的进程并释放了内存,刚刚我回去看任务管理器,内存占用已经回到⓪.①M了。所以我觉得这就是Windows的进程内存管理方式:空闲内存①段时间不用,或者可能windows本身开新进程内存不够的时候,才会触发进程空闲内存回收,否则会维持现状
(想想要是那时候的我知道进程退出之前不需要手动释放内存,可能就不会发现这个小问题了)
编后语:关于《咋样可以很好地理解编程中的递归呢?这段C++代码 调用递归的过程》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。 下一篇内容是有关《如何评价已经发布的小米手机6?小米手机总是发烫咋办》,感兴趣的同学可以点击进去看看。
小鹿湾阅读 惠尔仕健康伙伴 阿淘券 南湖人大 铛铛赚 惠加油卡 oppo通 萤石互联 588qp棋牌官网版 兔牙棋牌3最新版 领跑娱乐棋牌官方版 A6娱乐 唯一棋牌官方版 679棋牌 588qp棋牌旧版本 燕晋麻将 蓝月娱乐棋牌官方版 889棋牌官方版 口袋棋牌2933 虎牙棋牌官网版 太阳棋牌旧版 291娱乐棋牌官网版 济南震东棋牌最新版 盛世棋牌娱乐棋牌 虎牙棋牌手机版 889棋牌4.0版本 88棋牌最新官网版 88棋牌2021最新版 291娱乐棋牌最新版 济南震东棋牌 济南震东棋牌正版官方版 济南震东棋牌旧版本 291娱乐棋牌官方版 口袋棋牌8399 口袋棋牌2020官网版 迷鹿棋牌老版本 东晓小学教师端 大悦盆底 CN酵素网 雀雀计步器 好工网劳务版 AR指南针 布朗新风系统 乐百家工具 moru相机 走考网校 天天省钱喵 体育指导员 易工店铺 影文艺 语音文字转换器