JS中的递归
递归基础
递归的概念
- 在程序中函数直接或间接调用自己
- 直接调用自己
- 简介调用自己
- 跳出结构,有了跳出才有结果
递归的思想
- 递归的调用,最终还是要转换为自己这个函数
- 如果有个函数foo,如果他是递归函数,到最后问题还是转换为函数foo的形式
- 递归的思想就是将一个未知问题转换为一个已解决的问题来实现
function foo(){
...foo(...)...
}
递归的步骤(技巧)
1. 假设递归函数已经写好
2. 寻找递推关系
3. 将递推关系的结构转换为递归体
4. 将临界条件加入到递归体中
简单递归练习
求1-100的和
分析:
- 假设递归函数已经写好为sum,既sum(100),就是求1-100的和
寻找递推关系: 就是 n 与 n-1 ,或 n-2 之间的关系
sum(n) == sum(n-1) + nvar res = sum(100);
var res = sum(99) + 100;
将递归结构转换成递归体
function sum(n){
return sum(n-1) + n;
}- 将临界条件加入到递归中
- 求100 转换为 求99
- 求99 转换为 求98
- 求98 转换为 求97
- ...
- 求2 转换为 求1
- 求1 转换为 求1
- 即 sum(1) = 1
递归函数
function sum(n){
if(n==1) return 1;
return sum(n-1) + n;
}求 1,3,5,7,9,...第n项的结果和前n项和,序号从0开始
- 分析
- 假设递归函数已经完成foo(n),得到奇数
- 递归关系:
- foo(n) = foo(n-1)+2
递归体
function foo(n){
return foo(n) = sum(n-1)+2;
}
- 跳出条件
- foo(n) = foo(n-1) + 2
- foo(1) = foo(0) + 2
- foo(0) = 1;
递归函数
function foo(n){
if(n == 0) return 1;
return foo(n-1) + 2;
}- 前 n 项的和
- 分析
- 假设完成,sum(n)就是前n项的和
- 递推关系
- foo(n) = sum(n) + 第n-1项之前的和
递归体
function sum(n){
return foo(n) + sum(n-1);
}- 临界条件
- n == 1 ,结果为1
递归函数
```
function foo(n){
if(n == 0) return 1;
return foo(n-1) + 2;
}
function sum(n){
if(n == 0) return 1;
return foo(n) + sum(n-1);
}
```求 2,4,6,8,10... 第n项与前n项之和
- 分析
- 假设已知函数 fn(n)为第n项,sum(n)为前n项之和
- 递归关系
- fn(n) = fn(n-1) + 2
- sum(n) = fn(n) + sum(n-1)
- 递归体
function fn(n){
return fn(n) = (n-1) + 2
}
function sum(n){
return sum(n) = fn(n) + sum(n-1);
}
- 临界条件
- fn(0) = 2
- sum(0) = 2;
- 递归函数
```
function fn(n){
if(n == 0) return 2;
return fn(n-1) + 2;
}
function sum(n){
if(n==0) return 2;
return fn(n) + sum(n-1);
}
## 数列 1,1,2,4,7,11,16...求第 n 项,求前n项和
* 分析
1. 假设已知函数 foo(n) 为第n项
2. 递归关系
**从第 0 项开始计算**
* 第 0 项, 1 => foo(0) + 0 = foo(1)
* 第 1 项, 2 => foo(1) + 1 = foo(2)
* 第 2 项, 3 => foo(2) + 2 = foo(3)
* ...
* 第 n-1 项, n => foo(n-1) + n-1 = foo(n)
* foo(n) = foo(n-1) + n-1;
**从第 1 项开始计算**
* 第 1 项, 2 => fn( 1 ) + 0 = fn( 2 )
* 第 2 项, 3 => fn( 2 ) + 1 = fn( 3 )
* 第 3 项, 4 => fn( 3 ) + 2 = fn( 4 )
* ...
* foo(n) = fn(n-1) + n - 2
* 如果从 0 开始
0 1 2 3 4 5 6
1, 1, 2, 4, 7, 11, 16,
* 如果从 1 开始
1 2 3 4 5 6 7
1, 1, 2, 4, 7, 11, 16
3. 递归体
function foo(n){
return foo(n-1)+n-1;
}
4. 临界条件
* foo(0) == 1;
* foo(1) == 1;
5. 递归函数
function foo(n){
if(n == 0) return 1;
return foo(n-1) + n -1;
}
* 分析
1. 假设已知函数 sum(n)为前n项和
2. 递归关系
* sum(n) = foo(n) + sum(n-1);
3. 递归体
function sum(n){
return foo(n) + sum(n-1);
}
4. 临界条件
* sum(0) = 1;
5. 递归函数
function sum(n){
if(n == 0) return 1;
return foo(n) + sum(n-1);
}
## Fibonacci数列(斐波那契数列)
1,1,2,3,5,8,13,21,34,55,89...求第 n 项
* 分析
1. 假设已知 fib(n) 为第 n 项
2. 递归关系
* fib(n) = fib(n-1) + fib(n-2)
3. 递归体
function fib(n){
return fib(n-1)+fib(n-2);
}
4. 临界条件
* fib(0) == 1
* fib(1) == 1
5. 递归函数
function fib(n){
if(n == 0 || n ==1) return 1;
return fib(n-1) + fib(n-2);
}
# 高级递归练习
## 阶乘
概念:
* 阶乘是一个运算, 一个数字的阶乘表示的是从 1 开始 累乘到这个数字.
* 例如 3! 表示 `1 * 2 * 3`. 5! 就是 `1 * 2 * 3 * 4 * 5`. 规定 0 没有阶乘,
* 阶乘 从 1 开始.
* 分析:
1. 假设已知 foo(n) 为 1-n 的积
2. 递归关系
* foo(n) = foo(n-1) * n
3. 递归体
function foo(n){
return foo(n-1) * n
}
4. 临界条件
* foo(1) == 1
5. 递归函数
function foo(n){
if( n == 1) return 1;
return foo(n - 1) * n;
}
## 求幂
* 概念:
求幂就是求 某一个数 几次方
2*2 2 的 平方, 2 的 2 次方
求 n 的 m 次方
最终要得到一个函数 power( n, m )
n 的 m 次方就是 m 个 n 相乘 即 n 乘以 (m-1) 个 n 相乘
* 分析
1. 假设已知函数 power(n,m) 为 n 的 m 次幂
2. 递归关系
* power(n,m-1) * n
3. 递归体
function power(n,m){
return power(n,m-1) * n;
}
4. 临界条件
* m == 1 ,return n
* m == 0 ,reutnr 1
5. 递归函数
function power(n,m){
if(m == 1) return n;
return power(n,m-1) * n;
}
# 深拷贝,使用递归方式
概念:
1. 如果拷贝的时候, 将数据的所有引用结构都拷贝一份, 那么数据在内存中独立就是深拷贝(内存隔离,完全独立)
2. 如果拷贝的时候, 只针对当前对象的属性进行拷贝, 而属性是引用类型这个不考虑, 那么就是浅拷贝
3. 拷贝: 复制一份. 指将对象数据复制.
4. 在讨论深拷与浅拷的时候一定要保证对象的属性也是引用类型.
实现方法:
5. 如果要实现深拷贝那么就需要考虑将对象的属性, 与属性的属性,都拷贝过来
6. 分析(2个参数,简单实现)
1. 假设已经实现 clone ( o1, o2),将对象 o2 的成员拷贝一份交给 o1
2. 递推关系
* 混合方法,将 o2 的成员拷贝到 o1 中
```
function clone( o1, o2){
for(var key in o2){
o1[key] = o2[key];
}
}
```
* 假设方法已经实现,如果 o2[key] 是对象
* 继续使用这个方法
* 需要考虑 o2[key] 是引用类型,再一次使用clone函数
* 如果 o2[key] 不是引用类型,那么直接赋值
3. 临界条件
* 因为是 for in 循环,没有成员遍历时,自动结束
4. 递归函数
function clone(o1,o2){
for(var key in o2){
if(typeof o2[key] == 'object'){
o1[key] = {};
clone(o1[key],o2[key])
}else{
o1[key] = o2[key];
}
}
}
复杂实现(一个参数)
原理: clone(o) = new Object; 返回一个对象
递归函数
function clone(o){
var temp = {};
for(var key in o){
if(typeof o[key] == 'object'){
temp[key] = clone(o[key]);
}else{
temp[key] = o[key];
}
}
return temp;
}
# 使用递归实现 getElementsByClassName
html结构:
<div>
<div>1
<div class="c">2</div>
<div>3</div>
</div>
<div class="c">4</div>
<div>5
<div>6</div>
<div class="c">7</div>
</div>
<div>8</div>
</div>
分析
1. 实现一个方法byClass()需要的参数是:
node: 在某个节点上寻找元素
className: 需要寻找的className
arr: 找到的元素存储到这个数组中
2. 遍历 node 的子节点,
3. 查看这个子节点是否还有子节点,如果没有直接存储到数组中,如果有就继续递归
var arr = [];
function byClass(node, className, arr){
//得到传入节点的所有子节点
var lists = node.childNodes;
for(var i = 0;i< lists.length;i++){
//判断是否有相同className元素
if(arr[i],className == className){
arr.push(arr[i]);
}
//判断子节点是否还有子节点
if(arr[i].childNodes.length > 0){
byClass(arr[i],className,arr);
}
}
}
```
JS中的递归的更多相关文章
- js中的递归总结
主要从"变量+函数"和"函数+变量"两个方面说明解释. function fun() { // 自己调用自己,称为递归调用 fun(); console.log ...
- 如何在js中使用递归
很久没写博客了... 内容后补
- 【授课录屏】JavaScript高级(IIFE、js中的作用域、闭包、回调函数和递归等)、MySQL入门(单表查询和多表联查)、React(hooks、json-server等) 【可以收藏】
一.JavaScript授课视频(适合有JS基础的) 1.IIFE 2.js中的作用域 3.闭包 4.表达式形式函数 5.回调函数和递归 资源地址:链接:https://pan.baidu.com/s ...
- java、js中实现无限层级的树形结构(类似递归)
js中: var zNodes=[ {id:0,pId:-1,name:"Aaaa"}, {id:1,pId:0,name:"A"}, {id:11,pId:1 ...
- js中reduce()的牛掰所在 本质作用:实现数值累计,筛选过滤,类似递归
先看w3c官说 array.reduce(function(total, currentValue, currentIndex, arr), initialValue); /* total: ...
- 浅解析js中的对象
浅解析js中的对象 原文网址:http://www.cnblogs.com/foodoir/p/5971686.html,转载请注明出处. 前面的话: 说到对象,我首先想到的是每到过年过节见长辈的时候 ...
- 别再为了this发愁了------JS中的this机制
别再为了this发愁了------JS中的this机制 题记:JavaScript中有很多令人困惑的地方,或者叫做机制.但是,就是这些东西让JavaScript显得那么美好而与众不同.比方说函数也是对 ...
- 对js中Function的浅见
它到底是什么 String Array 都是系统内置对象(已经定义好,可以直接使用)当然,这货也是一样,我们之前定义的函数,其实就是一个这货的实例. 在JS中,所有的对象都是由函数实现的,函数的数据类 ...
- js中的排序
不靠谱的sort() 众所周知,js中的sort()排序是按字母表顺序排序的,这就导致如下现象: var a = [9,60,111,55,8,7777]; a.sort(); alert(a); / ...
随机推荐
- 大数运算的算法设计和C++实现
1.背景 工作中遇到过需要进行极大数据的存储和运算的场景,当时使用Python解决了这个问题,在Python中,整数没有位数限制,使用起来很方便.但是当程序主体使用C/C++实现时,就比较麻烦.所以考 ...
- Flashing Back a Failed Primary Database into a Physical Standby Database(闪回FAILOVER失败的物理备库)
文档操作依据来自官方网址:https://docs.oracle.com/cd/E11882_01/server.112/e41134/scenarios.htm#SBYDB4888 闪回FAILOV ...
- web语义化之SEO和ARIA
在快速理解web语义化的时候,只知道web语义化有利于SEO和便于屏幕阅读器阅读,但并不知道它是如何有利于SEO和便于阅读器阅读的,带着这个疑问,进行了一番探索总结. SEO 什么是SEO? SEO( ...
- 假设检验(Hypothesis Testing)
假设检验(Hypothesis Testing) 1. 什么是假设检验呢? 假设检验又称为统计假设检验,是数理统计中根据一定假设条件由样本推断总体的一种方法. 什么意思呢,举个生活中的例子:买橘子(借 ...
- java 中的JDK封装的数据结构和算法解析(集合类)----链表 List 之 Vector (向量)
Vector 看JDK解释(中文翻译)吧: Vector 类可以实现可增长的对象数组.与数组一样,它包含可以使用整数索引进行访问的组件.但是,Vector 的大小可以根据需要增大或缩小,以适应创建 ...
- 『练手』通过注册表 获取 VS 和 SQLServer 文件路径
获取任意 VS 和 SQLServer 的 磁盘安装目录. 背景需求:如果磁盘电脑安装了 VS 或者 SQLServer 则 认定这台计算机 的使用者 是一名 软件研发人员,则让程序 以最高权限运行. ...
- JavaScript(第二十四天)【事件对象】
JavaScript事件的一个重要方面是它们拥有一些相对一致的特点,可以给你的开发提供更多的强大功能.最方便和强大的就是事件对象,他们可以帮你处理鼠标事件和键盘敲击方面的情况,此外还可以修改一般事件的 ...
- C语言——第四次作业
题目 题目一:计算分段函数 1.实验代码 #include <stdio.h> int main() { double x,y; scanf("%lf",&x) ...
- Flask 学习 五 电子邮件
pip install mail from flask_mail import Mail # 邮件配置 app.config['MAIL_SERVER']='smtp.qq.com' app.conf ...
- JAVA中最容易让人忽视的基础。
可能很多找编程工作的人在面试的时候都有这种感受,去到一个公司填写面试试题的时候,多数人往往死在比较基础的知识点上.不要奇怪,事实就是如此一般来说,大多数公司给出的基础题大概有122道,代码题19道左右 ...