从"汉诺塔"经典递归到JS递归函数
前言
参考《JavaScript语言精粹》
递归是一种强大的编程技术,他把一个问题分解为一组相似的子问题,每一问题都用一个寻常解去解决。递归函数就是会直接或者间接调用自身的一种函数,一般来说,一个递归函数调用自身去解决它的子问题。
"汉诺塔"经典递归问题
"汉诺塔"是印度的一个古老传说,也是程序设计中的经典的递归问题,是一个著名的益智游戏:
题目如下:
塔上有三根柱子和一套直径各不相同的空心圆盘,开始时源柱子上的所有圆盘都按从大到小的顺序排列。目标是通过每一次移动一个圆盘到另一根柱子上,最终把一堆圆盘移动到目标柱子上,过程中不允许把较大的圆盘放置在较小的圆盘上;

寻找规律(把所有的圆盘移动到C):
1)n(圆盘个数) == 1
第一次:1号盘 A -> C sum(移动次数) = 1
2)n == 2
第一次:1号盘 A -> B
第二次:2号盘 A -> C
第三次:1号盘 B -> C sum = 3
3)n == 3
第一次:1号盘 A -> C
第二次:2号盘 A -> B
第三次:1号盘 C -> B
第四次:3号盘 A -> C
第五次:1号盘 B -> A
第六次:2号盘 B -> C
第七次:1号盘 A -> C sum = 7
故不难发现规律,移动次数为:sum = 2^n - 1
算法分析(递归):
把一堆圆盘从一个柱子移动另一根柱子,必要时使用辅助的柱子。可以把它分为三个子问题:
首先,移动一对圆盘中较小的圆盘到辅助柱子上,从而露出下面较大的圆盘,
其次,移动下面的圆盘到目标柱子上
最后,将刚才较小的圆盘从辅助柱子上在移动到目标柱子上
把三个步骤转化为简单数学问题:
(1) 把 n-1个盘子由A 移到 B;
(2) 把 第 n个盘子由 A移到 C;
(3) 把n-1个盘子由B 移到 C;
我们创建一个JS函数,当它调用自身的时候,它去处理当前正在处理圆盘之上的圆盘。最后它回一个不存在圆盘去调用,在这种情况下,它不在执行任何操作。
JavaScript源代码实现
var hanoi = function(disc,src,aux,dst){
if(disc>0){
hanoi(disc-1,src,dst,aux);
console.log(' 移动 '+ disc + ' 号圆盘 ' + ' 从 ' + src + ' 移动到 ' + dst);
hanoi(disc-1,aux,src,dst)
}
}
hanoi(3,'A','B','C')

整个算法的思路是:
- 将A柱子上的n-1个盘子暂时移到B柱子上
- A柱子只剩下最大的盘子,把它移到目标柱子C上
- 最后再将B柱子上的n-1

JS递归函数遍历Dom
递归函数可以非常高效的操作D树形结构,在JavaScript有一种"天然的树形结构"浏览器端的文档对象模型(Dom)。每次递归调用时处理指定树的一小段。
/* 我们定义一个walk_the_DOM函数,
1) 它从某个指定的节点开始,按指定HTML源码的顺序,访问树的每个节点
2)它会调用一个函数,并依次传递每个节点给它,walk_the_DOM调用自身去处理每一个节点
*/
var walk_the_DOM = function walk( node , func ) {
func(node);
node = node.firstChild;
while (node) {
walk( node , func );
node = node.nextSibling;
}
}
/* 在定义一个getElementByAttribute函数
1) 它以一个属性名称字符串和一个可选的匹配值作为参数
2) 它调用walk_the_DOM,传递一个用来查找节点属性名的函数作为参数,匹配得节点都会累加到一个数组中
*/
var getElementsByAttribute=function(att,value){
var results=[];
walk_the_DOM(document.body,function(node){
var actual=node.nodeType===1&&node.getAttribute(att);
if(typeof actual==='string' &&( actual===value|| typeof value!=='string')){
results.push(node);
}
});
return results;
}
命名函数表达式和递归
递归问题
求阶乘的函数:
function factorial(num){
if(num<=1){
return 1;
}else{
return num*factorial(num-1);
}
}
通过将函数factorial设置为null,使原始函数的引用只剩一个, 此时factorial已不再是函数

arguments.callee实现递归
arguments.callee是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用
function factorial(num){
if(num<=1){
return 1;
}else{
return num*arguments.callee(num-1);
}
}
var anotherFactorial=factorial;
factorial=null;
anotherFactorial(3)
用arguments.callee代替函数名,可以确保无论怎样调用函数都不会出问题。因此,在编写递归函数时,使用arguments.callee总比使用函数名更保险。
但是在严格模式下,不能通过脚本访问arguments.callee,访问这个属性会报错

命名函数表达式实现递归
创建一个名为f()的命名函数表达式,然后赋值给factorial,即使把函数赋值给了另一个变量,函数的名字f仍然有效,所以递归调用照样能正常完成。
这种方式在严格模式和非严格模式都可行。
var factorial =function f(num){
'use strict'
if(num<=1){
return 1;
}else{
return num* f (num-1);
}
}
factorial(3
var anotherFactorial=factorial;
factorial=null;
anotherFactorial(3
从"汉诺塔"经典递归到JS递归函数的更多相关文章
- 用C语言实现汉诺塔自动递归演示程序
用C语言实现汉诺塔自动递归演示程序 程序实现效果 1.变界面大小依照输入递归数改变. 2.汉诺塔自动移动演示. 3.采用gotoxy实现流畅刷新. 4.保留文字显示递归流程 程序展示及实现 githu ...
- Hanio汉诺塔代码递归实现
1.背景介绍 Hanio (汉诺塔,又称河内塔)问题是源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆罗门把圆盘 ...
- CODEVS 3145 汉诺塔游戏 递归
题目描述 Description 汉诺塔问题(又称为河内塔问题),是一个大家熟知的问题.在A,B,C三根柱子上,有n个不同大小的圆盘(假设半径分别为1-n吧),一开始他们都叠在我A上(如图所示),你的 ...
- HDU 2064 汉诺塔III(递归)
题目链接 Problem Description 约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下.由小到大顺序串着由64个圆盘构成的塔.目的是将最左边杆上的盘 ...
- 【Python实践-3】汉诺塔问题递归求解(打印移动步骤及计算移动步数)
# -*- coding: utf-8 -*- #汉诺塔移动问题 # 定义move(n,a,b,c)函数,接受参数n,表示3个柱子A.B.C中第1个柱子A的盘子数量 # 然后打印出把所有盘子从A借助B ...
- 汉诺塔问题-递归实现-JAVA
public class hanio { /** * @param args */ public static void main(String[] args) { // TODO Auto-gene ...
- Python 实现汉诺塔问题(递归)
有三根柱子一次为A,B,C 现在A柱子上有3个块,按照汉诺塔规则移动到C柱子上去,打印步骤? 我们这样理解:A为原始柱,C为目标柱,B为缓冲柱 1.定义一个函数move(n,a,b,c),n为原始柱上 ...
- 3145 code[VS]汉诺塔游戏--递归
3145 汉诺塔游戏 题目描述 Description 汉诺塔问题(又称为河内塔问题),是一个大家熟知的问题.在A,B,C三根柱子上,有n个不同大小的圆盘(假设半径分别为1-n吧),一开始他们都叠在我 ...
- hdu2064 汉诺塔Ⅲ(递归)
汉诺塔III Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
随机推荐
- [AOP系列]Autofac+Castle实现AOP事务
一.前言 最近公司新项目,需要搭架构进行开发,其中需要保证事务的一致性,经过一番查找,发现很多博文都是通过Spring.Net.Unity.PostSharp.Castle Windsor这些方式实现 ...
- 20170709_python_学习记录
a='ABC';变量赋值时发生了什么 1.在内存中创建一个字符串'ABC' 2.在内存中创建一个变量a指向字符串'ABC' list [] 相当于数组 指向可以变动 str[1,2,3,4] str. ...
- win10下安装python2与python3以及pip共存
一 分别安装python2和python3 注意: 安装时记得勾选 Add Python.exe to Path 二 安装pip Python3最新版本有pip,无需安装 Python2: 下载pip ...
- 动态语言的灵活性是把双刃剑 -- 以Python语言为例
本文有些零碎,总题来说,包括两个问题:(1)可变对象(最常见的是list dict)被意外修改的问题,(2)对参数(parameter)的检查问题.这两个问题,本质都是因为动态语言(动态类型语言)的特 ...
- luogu P1361 小猫爬山 [iddfs]
题目描述 WD和LHX饲养了N只小猫,这天,小猫们要去爬山.经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了. WD和LHX只好花钱让它们坐索道下山.索道上的缆车最大承重量为W ...
- 搭建私有Docker Registry
Docker官方提供了用于搭建私有registry的镜像,并配有详细文档. 官方Registry镜像:https://hub.docker.com/_/registry 官方文档:https://do ...
- (转)Spring的单例模式底层实现
单例模式也属于创建型模式,所谓单例,顾名思义,所指的就是单个实例,也就是说要保证一个类仅有一个实例. 单例模式有以下的特点: ① 单例类只能有一个实例 ② 单例类必须自己创建自己的唯一实例 ③ 单例类 ...
- Maven在导入其他项目时报错:Plugin execution not covered by lifecycle configuration
这几天想把Spring 攻略第二版完整的学习下,所以就在网上下载了该教材的源码,寻思边看书边练习!之前有过一些Maven开发的相关经验,觉得Maven在引入jar包上的配置还是很方便的,所以这次源码的 ...
- php 设计模式之策略模式
策略模式:定义算法,并将其封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 步骤:1.抽象策略角色:定义接口或抽象类 2.具体策略角色:实现该接口(抽象类),即具体的算法实现 ...
- CSS随笔1(CSS常用样式)
样式 属性 大小 font-size(x-large ; xx-small ; 可用数值单位 : PX,PD) 样式 font-style(oblique 偏斜体 : italic 斜体 : norm ...