更多例子

第二个递归的例子是求两个自然数的最大公约数(有没有回到令人怀念的中学时代)。下面的程序用的是经典的辗转相除法。

//greatest common divisor
//假定a、b都是正整数
function gcd(a, b){
if (a < b) return gcd(b, a);//ensure a >= b
var c = a % b;
if (c === 0)
return b;
else
return gcd(b, c);
}

除了上面这些条件或者解法可以转化为数学的递归定义的计算,递归方法还适用于其所涉及的数据结构即是以递归形式定义的问题,比如链表、图、树等等。

现在我们来看一个迷宫的例子。迷宫可以抽象成一副数学上的图,每个岔路口是一个点,其间的路是边。两个特殊的点,分别被定义成入口和出口。

下面是用Javascript定义的点和图。每个点包含一个id作为编号和标志,相邻的点被保存在一个数组中。图有一个添加点的方法,和一个更方便使用的直接添加点的id的方法;还有一个添加边的方法。

//define a vertex
function Vertex(id){
var stem={};
stem.id=id;
stem.adjacent=[];
return stem;
}
//define a graph
function Graph(){
var stem={}, vertices={};
//add vertices to the graph
function add(vertex){
if (vertex instanceof Array){
for (var i=0, v=vertex; i<v.length; i++){
vertices[v[i].id]=v[i];
}
}
vertices[vertex.id]=vertex;
}
//create vertices from ids and add them to the graph
function addIds(ids){
var id;
for (var i=0; i<ids.length; i++){
id=ids[i];
vertices[id]=Vertex(id);
}
}
//create an edge between two vertices
function connect(i1, i2){
var v1=vertices[i1], v2=vertices[i2];
if (v1 && v2){
v1.adjacent.push(v2);
v2.adjacent.push(v1);
}
}
stem.vertices=vertices;
stem.add=add;
stem.addIds=addIds;
stem.connect=connect;
return stem;
}

我们走出迷宫的思路是从入口开始,遍历每个点所有相邻的点,直到找到出口。因为图可能会包含环,也就是在迷宫中会出现兜圈子的情况,所以程序中记录每个到过的点,如果再次遇上,则返回上一个点。如果遇到出口,则退出整个遍历,返回到入口,途中记录经过的每个点,并最终写出从入口到出口的路线。这不是一个最优的办法,得到的结果未必是最短的路线,但是只要入口和出口之间是连通的,就一定可以找到一条路线。

//try to walk out of the maze and print the result
function walkOut(entry, exit){
var visited = [], path = []; function walk(vertex){
if (vertex === exit) {//find the exit
path.push(vertex);
return true;
}
if (visited.indexOf(vertex) > -1) {//the vertex was visited
return false;
}
visited.push(vertex);//remember each vertex
var connected = vertex.adjacent;
var length = connected.length;
if (length === 0) {//the vertex is isolated
return false;
}
for (var i = 0; i < length; i++) {
if (walk(connected[i])) {//try each adjacent vertex
path.push(vertex);
return true;
}
}
} function printPath(){
var footprint = '';
var length = path.length;
for (var i = length - 1; i > -1; i--) {
footprint += path[i].id;
footprint += i === 0 ? '' : ' > ';
}
print(footprint);
} if (walk(entry)) {
printPath();
}
else {
print('出不去!');
}
}

我们可以试验一下这段代码走迷宫的能力。

function testMaze(){
var g=Graph();
g.addIds([1, 2, 3, 4, 5, 6]);
g.connect(1, 2);
g.connect(1, 3);
g.connect(1, 4);
g.connect(2, 3);
g.connect(3, 5); //你可以画出这个图
walkOut(g.vertices[1], g.vertices[5]);//1 > 2 > 3 > 5
walkOut(g.vertices[1], g.vertices[6]);//出不去!
walkOut(g.vertices[2], g.vertices[5]);//2 > 1 > 3 > 5
}

在现实生活中,我们当然也可以用这种笨办法走出任何一个可能走出的迷宫,只要你用笔和便签纸在每一个岔路口记下你选择的路线。

JavaScript的递归之更多例子的更多相关文章

  1. Javascript中递归造成的堆栈溢出及解决方案

    关于堆栈的溢出问题,在Javascript日常开发中很常见,Google了下,相关问题还是比较多的.本文旨在描述如何解决此类问题. 首先看一个实例(当然你可以使用更容易的方式实现,这里我们仅探讨递归) ...

  2. 每天一个JavaScript实例-递归实现反转数组字符串

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  3. Javascript函数式编程的一些例子[转载]

    函数式编程风格 通常来讲,函数式编程的谓词(关系运算符,如大于,小于,等于的判断等),以及运算(如加减乘数等)都会以函数的形式出现,比如:    a > b通常表示为:    gt(a, b)/ ...

  4. javascript memoization递归优化

    memoize优化递归 function createRec(callback, cache) { cache = cache || []; var rec = function(n) { (n in ...

  5. javascript dom追加内容的例子

    javascript dom追加内容的使用还是比较广泛的,在本文将为大家介绍下具体的使用方法. 例子: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML ...

  6. 前端笔试题目总结——应用JavaScript函数递归打印数组到HTML页面上

    数组如下: var item=[{ name:'Tom', age:70, child:[{ name:'Jerry', age:50, child:[{ name:'William', age:20 ...

  7. [译]Javascript中闭包的各种例子

    本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...

  8. 一个javascript继承和使用的例子

    继承可以帮助我们实现代码的重用,把对象的属性写入构造函数,对象的方法写入原型后,以下例子演示继承的使用: 示例的css和js在后 父实例,得到一个间隔1s的轮播: <!DOCTYPE html& ...

  9. JavaScript对象---递归遍历对象

    JavaScript 中的所有事物都是对象:字符串.数值.数组.函数... 此外,JavaScript 允许自定义对象. JavaScript 对象 JavaScript 提供多个内建对象,比如 St ...

随机推荐

  1. BZOJ 3969 Low Power 解题报告

    我们首先将所有电池排序,那么我们可以找到一组最优方案,使得一台机器的能量之差是相邻两电池的能量之差. 然后我们就二分这个答案,从前往后贪心地选这个数对,然后看是否所有的数对都是满足条件的. 假设这个数 ...

  2. 九张图让你的PPT立刻高大上

  3. Python图形图像处理库的介绍之Image模块

    http://onlypython.group.iteye.com/group/wiki/1372-python-graphics-image-processing-library-introduce ...

  4. NSBundle的使用,注意mainBundle和Custom Bundle的区别

    1.[NSBundle mainBundle],文件夹其实是Group,如左侧的树形文件管理器 Build之后,文件直接就复制到了根目录下,于是读取的方法,应该是这样: NSString *earth ...

  5. Ubuntu 14.04数据库服务器--mysql的安装和配置

    mysql是Oracle公司的一种开放源代码的关系型数据库管理系统,被广泛应用于各中小网站,是一种跨平台的数据库管理系统,现在介绍一下如何在Ubuntu 14.04上安装和配置mysql 1. 更新源 ...

  6. VC多文档编程技巧(取消一开始时打开的空白文档)

    VC多文档编程技巧(取消一开始时打开的空白文档) http://blog.csdn.net/crazyvoice/article/details/6185461 VC多文档编程技巧(取消一开始时打开的 ...

  7. Android开发UI之个性化控件之Menu

    MenuDrawer 滑出式菜单,通过拖动屏幕边缘滑出菜单,支持屏幕上下左右划出,支持当前View处于上下层,支持Windows边缘.ListView边缘.ViewPager变化划出菜单等. 项目地址 ...

  8. scp传入固件,sysupgrade xx.bin升级固件

    scp传入固件,sysupgrade xx.bin升级固件

  9. 在Eclipse中使用Github(EGit)

    安装配置EGit 1. 安装Windows版的Git,登陆Github账号,登陆成功后会自动在本地和Github配置好密钥 2. 在Eclipse中安装EGit,地址http://download.e ...

  10. [liu yanling]测试方法

    1.定义 是把所有可能的输入数据,即程序的输入域划分成若干部分(子集),然后从每一个子集中选取少数具有代表性的数据作为测试用例.该方法是一种重要的,常用的黑盒测试用例设计方法. 2.划分等价类 等价类 ...