二级结论高中数学 递归数列( 二 )


1.首先,n-1个磁盘在C的帮助下成功地从A移动到B2,然后第n个磁盘从A移动到C3,最后,n-1个磁盘在A的帮助下成功地从B移动到C
那么如何编写代码呢?我们知道这个函数 。
Hanoi(n,' A ',' B ',' C ')表示N个圆盘通过B成功地从A移动到C 。
所以hanoi(n-1,' A ',' C ',' B ')的意思是n-1个磁盘在C的帮助下成功地从A移动到B 。
Hanoi(n-1,' B ',' A ',' C ')表示n-1个磁盘通过A成功地从B移动到C 。
所以上面的三个步骤可以用这样的代码来表达 。
1,hanoi(n-1,' A ',' C ',' B')2,System.out.println("从"+A+"移动到"+C ");3,河内(n-1,“B”,“A”,“C”)
所以最终完整的代码如下
1//表示的是把n个圆盘借助柱子B成功的从A移动到C2publicstaticvoidhanoi(intn,charA,charB,charC){3if(n==1){4//如果只有一个,直接从A移动到C即可5System.out.println("从"+A+"移动到"+C);6return;7}8这里是递归调用9}//表示的是把n个圆盘借助柱子B成功的从A移动到Cpublicstaticvoidhanoi(intn,charA,charB,charC){if(n==1){//如果只有一个,直接从A移动到C即可System.out.println("从"+A+"移动到"+C);return;}//表示先把n-1个圆盘成功从A移动到Bhanoi(n-1,A,C,B);//把第n个圆盘从A移动到CSystem.out.println("从"+A+"移动到"+C);//表示把n-1个圆盘再成功从B移动到Chanoi(n-1,B,A,C);}通过上面的分析,你是不是觉得递归很简单?所以我们写递归的时候,完全可以套用上面的模板,先写终止条件,再写递归的逻辑调用 。还有一点很重要,就是一定要理解递归函数中每个参数的含义,这样在逻辑处理和函数调用时才能得心应手 。一定不能一步一步把函数调用拆开来想,这样很有可能你会崩溃 。
4、二叉树的遍历
我们来看最后一个常见的例子,就是二叉树的遍历 。前面说了,有兴趣的话可以看看373,数据结构-6,还有树 。我们主要看二叉树的前、中、后三种遍历方法 。
1.我们来看一下前导遍历(根节点的开始) 。他的命令是
节点→左子树→右子树
让我们应用模板来看看 。
publicvoidpreOrder(TreeNodenode){if(终止条件)//(必须要有)return;逻辑处理//(不是必须的)递归调用//(必须要有)}终止条件是节点等于空,通过逻辑处理可以直接打印出当前节点的值 。递归调用是先打印左子树,再打印右子树 。让我们来看看 。
publicstaticvoidpreOrder(TreeNodenode){if(node==null)return;System.out.printf(node.val+"");preOrder(node.left);preOrder(node.right);}直接看中序遍历和后续遍历 。
2.中序遍历(根节点在中间)
左子树→根节点→右子树
publicstaticvoidinOrder(TreeNodenode){if(node==null)return;inOrder(node.left);System.out.println(node.val);inOrder(node.right);}3.按逆序遍历(根节点在末尾)
左子树→右子树→根节点
publicstaticvoidpostOrder(TreeNodetree){if(tree==null)return;postOrder(tree.left);postOrder(tree.right);System.out.println(tree.val);}5.链表的反向打印
这个我就不说了,看看就知道了 。
publicvoidprintRevers(ListNoderoot){//(终止条件)if(root==null)return;//(递归调用)先打印下一个printRevers(root.next);//(逻辑处理)把后面的都打印完了在打印当前节点System.out.println(root.val);}支流污染问题通过上面的分析,我们对递归有了更深的理解 。但是总觉得少了点什么 。其实我们可以用另一种方式来认识递归,那就是N树 。在递归中,如果我们只调用自己一次,我们可以把它看成一棵二叉树(这是我对自己的看法,我们可以把它看成一棵只有一个子节点的树) 。如果我们称自己两次,我们可以把它想象成一棵二叉树 。如果我们叫自己N次,我们可以把它想成一棵N叉树 。就像下面这样,到了叶子节点就开始反弹 。
如果递归处理不当,可能会导致分支污染和结果错误 。为什么会这样?我先解释一下,因为除了基本类型是值传递,其他很多类型基本都是引用传递 。看一下上图 。比如我开始调用的时候传入了一个list对象,调用第一个分支后,修改了列表中的数据,所以后续的所有分支都可以感知到,实际上对后续的分支造成了污染 。
我们先来看一个例子 。
给定数组nums = [2,3,5],固定值target=8 。找出数组sums中能使数字之和成为目标的所有组合 。我们画张图看看吧 。
图中的红色表示组合成功 。这里只画了选择2的分支 。因为图形太大,所以没有画出选择3和选择5的分支 。仔细一看,这不就是3-tree吗?好,我们用递归 。我们先来看看函数的定义 。
privatevoidcombinationSum(Listcur,intsums[],inttarget){}取出递归模板 。
privatevoidcombinationSum(Listcur,intsums[],inttarget){if(终止条件){return;}//逻辑处理//因为是3叉树,所以这里要调用3次//递归调用//递归调用//递归调用//逻辑处理}这种解决方案不太灵活 。如果nums的长度是3,我们递归调用它3次 。如果nums的长度是n,那么我们要调用它n次...所以我们可以直接把它写成for循环的形式,如下

推荐阅读