深度优先遍历 and 广度优先遍历
深度优先遍历 and 广度优先遍历
遍历在前端的应用场景不多,多数是处理
DOM节点数或者 深拷贝。下面笔者以深拷贝为例,简单说明一些这两种遍历。
深度优先遍历
想象有一颗节点树,从某个顶点开始,一直往下遍历,直到遍历到的节点都访问过后,往回走,遍历没有访问的节点,感觉很像递归。下面笔者就用递归实现 深度优先遍历。
function getRegExp(target){
var flat = '';
if(target.global) flat+='g';
if(target.ignoreCase) flat+='i';
if(target.multiline) flat+='m';
return target;
}
function DFS(target,visiteds){
var Type = Object.prototype.toString.call(target).slice(8,-1);
console.log(Type)
var copy = Type == 'Array'?[]:{};
visiteds = visiteds|| []; //处理环形数据,防止无限循环
switch(Type){
case 'Date':
copy = new Date(target.getTime());
break;
case 'RegExp':
copy = new RegExp(target.source,getRegExp(target));
break;
case 'Array':
case 'Object':
var index = visiteds.indexOf(target);
if(index>-1){
copy = visiteds[index];
}else{
visiteds.push(target);
for(var key in target){
copy[key] = DFS(target[key],visiteds);
}
}
break;
default:
copy = target;
break;
}
return copy;
};
来个es6版本的:
const deepClone = (obj, hash=new WeakMap()) =>{
if(obj instanceof RegExp) return new RegExp(obj);
if(obj instanceof Date) return new Date(obj);
if(typeof obj === 'function') return new Function('return '+obj.toString())();
if(obj === null || typeof obj !== 'object') return obj;
if(hash.has(obj)){
return hash.get(obj);
}
let t = obj.constructor();
hash.set(obj,t);
for(let k in obj){
if(obj.hasOwnProperty(k)){
t[k] = deepClone(obj[k],hash);
}
}
return t;
}
广度优先遍历
如果把
深度优先遍历看成纵向遍历,那么广度优先遍历就是横向遍历,一层一层的往下遍历。下面用队列(FIFO)来实现。
function getEmpty(o){
var Type = Object.prototype.toString.call(o).slice(8,-1);
if(Type === 'Object'){
return {};
}
if(Type === 'Array'){
return [];
}
if(Type==='Date'){
return new Date(o.getTime());
}
if(Type==='RegExp'){
return new RegExp(o.source,getRegExp(o))
}
return o;
}
function getRegExp(o){
var flat = '';
if(o.global) flat+='g';
if(o.ignoreCase) flat+='i';
if(o.multiline) flat+='m';
return o;
}
function BFS(target){
var queue = [];
var targetMap = []; //处理环形数据,防止无限循环
var copy = getEmpty(target);
if(copy!==target){
queue.push([target,copy]);
}
while(queue.length>0){
var [_target,_copy] = queue.shift(); //*
for(var key in _target){
var index = targetMap.indexOf(_target[key]);
if(index>-1){
_copy[key] = targetMap[index]
continue;
}
_copy[key] = getEmpty(_target[key])
if(_copy[key]!==_target[key]){
queue.push([_target[key],_copy[key]]); //*
targetMap.push(_target[key]);
}
}
}
return copy
}
总结
上面用两种不同的方法实现了深拷贝,但是只针对Object,Array的情况,其他的复杂对象没有考虑到,当然你也可以添加更多的处理,但笔者认为目前这样已经足够用了。。。
深度优先遍历,关键在于理解递归,而广度优先遍历,关键在于理解,queue.shift出去的数据保存着原来数据的引用,所以才能够在不断的进栈出栈中修改值(间接修改值)
深度优先遍历 and 广度优先遍历的更多相关文章
- js实现深度优先遍历和广度优先遍历
深度优先遍历和广度优先遍历 什么是深度优先和广度优先 其实简单来说 深度优先就是自上而下的遍历搜索 广度优先则是逐层遍历, 如下图所示 1.深度优先 2.广度优先 两者的区别 对于算法来说 无非就是时 ...
- C++ 二叉树深度优先遍历和广度优先遍历
二叉树的创建代码==>C++ 创建和遍历二叉树 深度优先遍历:是沿着树的深度遍历树的节点,尽可能深的搜索树的分支. //深度优先遍历二叉树void depthFirstSearch(Tree r ...
- 邻接矩阵c源码(构造邻接矩阵,深度优先遍历,广度优先遍历,最小生成树prim,kruskal算法)
matrix.c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include < ...
- C++编程练习(9)----“图的存储结构以及图的遍历“(邻接矩阵、深度优先遍历、广度优先遍历)
图的存储结构 1)邻接矩阵 用两个数组来表示图,一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中边或弧的信息. 2)邻接表 3)十字链表 4)邻接多重表 5)边集数组 本文只用代码实现用 ...
- js实现对树深度优先遍历与广度优先遍历
深度优先与广度优先的定义 首先我们先要知道什么是深度优先什么是广度优先. 深度优先遍历是指从某个顶点出发,首先访问这个顶点,然后找出刚访问这个结点的第一个未被访问的邻结点,然后再以此邻结点为顶点,继续 ...
- python、java实现二叉树,细说二叉树添加节点、深度优先(先序、中序、后续)遍历 、广度优先 遍历算法
数据结构可以说是编程的内功心法,掌握好数据结构真的非常重要.目前基本上流行的数据结构都是c和c++版本的,我最近在学习python,尝试着用python实现了二叉树的基本操作.写下一篇博文,总结一下, ...
- 【图的遍历】广度优先遍历(DFS)、深度优先遍历(BFS)及其应用
无向图满足约束条件的路径 •[目的]:掌握深度优先遍历算法在求解图路径搜索问题的应用 [内容]:编写一个程序,设计相关算法,从无向图G中找出满足如下条件的所有路径: (1)给定起点u和终点v. ( ...
- 二叉树的深度优先遍历与广度优先遍历 [ C++ 实现 ]
深度优先搜索算法(Depth First Search),是搜索算法的一种.是沿着树的深度遍历树的节点,尽可能深的搜索树的分支. 当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点 ...
- Dom的深度优先遍历和广度优先遍历
//深度优先遍历的递归写法 function DFTraversal(node) { var nodes = []; if (node != null) { nodes.push(node); var ...
随机推荐
- 【水滴石穿】LoginScreen_Firabase_ReactNativeApp_Redux
先看效果 分析代码我们会发现,它使用了firebase 关于登陆部分应该是实时数据库,应该是他们后端校验的 //app.js //这里使用了实时数据库 import React, { Componen ...
- 开启php中短标签<%%>和<??>的方法
<? ?> 短标签,兼容的,PHP默认也不支持,需要在php的配置文件中设置! 去到php.ini中开启下面的 <% %> ASP风格!也是兼容的,也需要配置:
- day40-Spring 02-事务的回顾
- sed 命令用法
Sed:对文件进行编辑操作,对象是行.操作后在屏幕输出结果.如果要直接修改则加-i命令-f filename: 执行某文件内的sed命令-n 只显示被修改的那一行 如文件test内容:Letyou a ...
- Codeforces 425B
点击打开题目链接 题意:给定一个n×m的0,1矩阵,做多可以对矩阵做k次变换,每次变换只可以将矩阵的某一个元素由0变成1,或从1变成0. 求最小的变换次数使得得到的矩阵满足:每一个连通块都是一个“实心 ...
- HDU 4193
本题思路:用sum[]数组维护前缀和, 当然这里需要把原数组扩大为原来的两倍. 然后对于任意一个长度为n的区间 k.....k+n-1,如果有该区间内的最小值大于等于sum[k-1]那么该种情况就符合 ...
- Oracle SQL——如何用一个表的数据更新另一个表中的数据
背景 一次处理数据的过程中,需要将表A(源表)的数据更新到表B(目标表)中 前提 两张表一定要有关联字段 使用关联字段联查两张表时,两张表关系必须满足条件:目标表和源表的表间关系一定是多对一或者一对一 ...
- hdu1730 尼姆博弈
抽象一下把距离当做石子个数.虽然在这里石子个数可以增加,但是不管怎么增加,不会影响结果,因为你增加了,必须会有减少的. 所以类似取石子,观察平衡状态,如果(x2-x1-1)^...==0,必输. wa ...
- SpringCloud Zuul 路由映射规则配置
阅读目录 前言 快速入门 路由详解 Cookie与头信息 本地跳转 Hystrix和Ribbon支持 过滤器解释 动态加载 后记 回到目录 前言 本文起笔于2018-06-26周二,接了一个这周要完成 ...
- 容器化ICT融合初体验
[编者的话]本次将分享的容器化ICT融合平台是一种面向未来ICT系统的新型云计算PaaS平台,它基于容器这一轻量级的虚拟化技术以及自动化的"微服务"管理架构,能够有效支撑应用快速上 ...