树结构之JavaScript
对于数据结构“树”,想必大家都熟悉,今儿,我们就再来回顾一下数据结构中的二叉树与树,并用JavaScript实现它们。
ps:树结构在前端中,很多地方体现得淋漓尽致,如Vue的虚拟DOM以及冒泡等等。
| 二叉树 |
--概念--
二叉树是一种树形结构,它的特点是每个结点至多只有两棵子树(即二叉树中不存在度大于2的结点),并且,二叉树的子树有左右之分,其次序不能任意颠倒。
如下,就是一棵二叉树(注:下文二叉树相关例子,都以该二叉树为例):

且,遍历二叉树(traversing binary tree)有三种常用方式,如下:
1)、先序遍历二叉树 (根左右)
若二叉树为空,则空操作;否则
--访问根结点;
--先序遍历左子树;
--先序遍历右子树。
例如,上述例子中的二叉树,遍历结果如下:

2)、中序遍历二叉树(左根右)
若二叉树为空,则空操作;否则
--中序遍历左子树;
--访问根结点;
--中序遍历右子树。
例如,上述例子中的二叉树,遍历结果如下:

3)、后序遍历二叉树(左右根)
若二叉树为空,则空操作;否则
--后序遍历左子树;
--后序遍历右子树;
--访问根结点。
例如,上述例子中的二叉树,遍历结果如下:

好了,了解了二叉树以及遍历方式,那么,接下来我们就一起用JavaScrip来实现下吧,当然采用链式存储结构。
首先,利用JavaScript构造函数建立二叉树结点,如下:
function TreeNode(){
this.data = null;//该节点数据
this.lchild = null;//左子树
this.rchild = null;//右子树
};
然后,我们可以通过遍历二叉树的算法,构建一棵二叉树,如下,采用先序序列建立一棵二叉树方法:
/*
*method:采用先序序列建立二叉树
*@params: nodeList(Array) --树节点,以先序序列存入数组中,null代表空节点
*/
TreeNode.createBiTree = function(nodeList){
var i = 0;
return (function getNode(){
var node = null,
val = nodeList[i++];
if(!val){
node = null;
}else{
node = new TreeNode();
node.data = val;
node.lchild = getNode();
node.rchild = getNode();
}
return node;
})();
};
最后,就是遍历一棵二叉树咯,分别为先序遍历(PreOrderTraverse)、中序遍历(InOrderTraverse)以及后序遍历(PostOrderTraverse),如下:
TreeNode.prototype = {
constructor: TreeNode,
_PreOrderTraverse: function(node){
if(node){
console.log(node.data);
this._PreOrderTraverse(node.lchild);
this._PreOrderTraverse(node.rchild);
}
},
PreOrderTraverse: function(){
console.log('PreOrder:');
this._PreOrderTraverse(this);
},
_InOrderTraverse: function(node){
if(node){
this._InOrderTraverse(node.lchild);
console.log(node.data);
this._InOrderTraverse(node.rchild);
}
},
InOrderTraverse: function(){
console.log('InOrder:');
this._InOrderTraverse(this);
},
_PostOrderTraverse: function(node){
if(node){
this._PostOrderTraverse(node.lchild);
this._PostOrderTraverse(node.rchild);
console.log(node.data);
}
},
PostOrderTraverse: function(){
console.log('PostOrder:');
this._PostOrderTraverse(this);
}
};
代码稍长,请自行打开
好了,利用上述二叉树例子,我们可以自行测试下:
var treeNode = null,
nodeList = ['A', 'B', 'C', null, null, 'D', 'E', null, 'G', null, null, 'F', null, null, null];
//getting a binary tree from nodeList
treeNode = TreeNode.createBiTree(nodeList);
//traversing the tree of treeNode
treeNode.PreOrderTraverse();//ABCDEGF
treeNode.InOrderTraverse();//CBEGDFA
treeNode.PostOrderTraverse();//CGEFDBA
| 树 |
--概念--
树是n(n>=0)个结点的有限集。在任意一棵非空树中,有且仅有一个特定的称为根(root)的结点,当n>1时,其余结点可分为m(m>0)个互不相交的有限集,其中每个集合本身又是一棵树,称为根的子树。当然,二叉树肯定属于树咯。
如下,就是一棵树(注:下文树的相关例子,都以该树为例):

且,遍历一棵多孩子树,有两种常用遍历方式,如下:
1) 、先根遍历,和深度优先搜索(Depth_First Search)遍历类似。都是利用栈来遍历元素,如下:

2) 、按层次遍历,和广度优先搜索(Breadth_First Search)遍历类似。都是利用队列来遍历元素,如下:

好了,了解了树以及遍历方式,那么,接下来我们就一起用JavaScrip来实现下吧,当然也是采用链式存储结构。
首先,利用JavaScript建立树结点,如下:
/*
*@Params: data --节点数据
children -- 所有孩子结点
*/
function TreeNode(data, children){
if(!(this instanceof TreeNode)){
return new TreeNode(data, children);
}
this.data = data || null;
this.children = children || [];
};
根据上述TreeNode构造函数,我们可以将例子中的树,表示如下:
var treeNode = TreeNode('A', [
TreeNode('B', [TreeNode('E')]),
TreeNode('C'),
TreeNode('D')
]);
接着,就是编写遍历树方法咯,分别为先根遍历和按层次遍历,如下:
TreeNode.prototype = {
constructor: TreeNode,
_traverseAsDFS: function(node){//先根遍历
var self = this;
if(node){
console.log(node.data);
node.children.forEach(function(child){
if(child.children.length){
self._traverseAsDFS(child);
}else{
console.log(child.data);
}
});
}
},
traverseAsDFS: function(){
console.log('Depth_First Search');
this._traverseAsDFS(this);
},
traverseAsBFS: function(){//按层次遍历
var queue = [];
console.log('Breadth_First Search');
console.log(this.data);
if(this.children.length){
queue.push(this);
}
while(queue.length){
let tempNode = queue.shift();
tempNode.children.forEach(function(child){
console.log(child.data);
if(child.children.length){
queue.push(child);
}
});
}
}
};
代码稍长,请自行打开
好了,利用上述二叉树例子,我们可以自行测试下:
var treeNode = TreeNode('A', [
TreeNode('B', [TreeNode('E')]),
TreeNode('C'),
TreeNode('D')
]);
treeNode.traverseAsDFS();//ABECD
treeNode.traverseAsBFS();//ABCDE
关于上述全部代码,见github。
树结构之JavaScript的更多相关文章
- 实现一个简单的虚拟DOM
现在的流行框架,无论React还是Vue,都采用虚拟DOM. 好处就是,当我们数据变化时,无需像Backbone那样整体重新渲染,而是局部刷新变化部分,如下组件模版: <ul class=&qu ...
- WEB前段(HTML+JS),后端(MYSQL+PHP)开发基础
一.HTML HTML:超文本标记语言,可以加载JS/CSS/图片/链接等非文字的内容 一切的网页开发技术都需要建立在HTML的基础之上 HTML的结构和语法 HTML元素 注释: <!-- ...
- JavaScript实现树结构(一)
JavaScript实现树结构(一) 一.树结构简介 1.1.简单了解树结构 什么是树? 真实的树: 树的特点: 树一般都有一个根,连接着根的是树干: 树干会发生分叉,形成许多树枝,树枝会继续分化成更 ...
- JavaScript实现树结构(二)
JavaScript实现树结构(二) 一.二叉搜索树的封装 二叉树搜索树的基本属性: 如图所示:二叉搜索树有四个最基本的属性:指向节点的根(root),节点中的键(key).左指针(right).右指 ...
- JavaScript遍历树结构
遍历 function parseTreeJson(treeNodes){ if(!treeNodes||!treeNodes.length)return; for(let i=0;i<tree ...
- 用JavaScript实现一个简单的树结构
数据源用数组混json结构,实现了基本的功能.效率一般,跟 dhtree 梅花雪树对比了下,都差不多. (ps感觉比dhtree快点,跟梅花雪树差不多,个人测试) 这个实现树的原理是根据json,不断 ...
- JavaScript 将行结构数据转化为树结构数据源(高效转化方案)
js接收到后台的数据如下 /// 部门信息 var departRows = [{ parentDepartId: 'root', departId: 'DC', departName: '集团' } ...
- react+redux教程(五)异步、单一state树结构、componentWillReceiveProps
今天,我们要讲解的是异步.单一state树结构.componentWillReceiveProps这三个知识点. 例子 这个例子是官方的例子,主要是从Reddit中请求新闻列表来显示,可以切换reac ...
- javascript性能优化-repaint和reflow
repaint(重绘) ,repaint发生更改时,元素的外观被改变,且在没有改变布局的情况下发生,如改变outline,visibility,background color,不会影响到dom结构渲 ...
随机推荐
- 安装maven和glassfish及配置环境变
首先搜索并下载maven3.6.0和glassfish4.1.1(版本看按需要选择). 点击安装包进行安装 安装完成后开始配置环境变量 打开系统环境变量 (1)新建系统变量MAVEN_HOME 变量值 ...
- sqlserver linux 容器运行
sqlserver linux 版本的容器大小目前已经相对比较小了,对于开发来说已经比较方便了 docker-compose 文件 version: "3" services: d ...
- NTLM 了解
NTLM是NT LAN Manager的缩写,这也说明了协议的来源.NTLM 是 Windows NT 早期版本的标准安全协议,Windows 2000 支持 NTLM 是为了保持向后兼容.Windo ...
- TensorFlow入门教程集合
TensorFlow入门教程之0: BigPicture&极速入门 TensorFlow入门教程之1: 基本概念以及理解 TensorFlow入门教程之2: 安装和使用 TensorFlow入 ...
- Centos7修改文件夹权限和用户名用户组
Linux系统下经常遇到文件或者文件夹的权限问题,或者是因为文件夹所属的用户问题而没有访问的权限.根据我自己遇到的情况,对这类问题做一个小结.在命令行使用命令“ll”或者“ls -a”,可以查看文件或 ...
- 网络基础 TCP/IP
为了理解 HTTP,我们有必要事先了解一下 TCP/IP 协议族.通常使用的网络(包括互联网)是在 TCP/IP 协议族的基础上运作的.而 HTTP 属于它内部的一个子集.接下来,我们仅介绍理解 HT ...
- ShareMemory
项目地址 : https://github.com/kelin-xycs/ShareMemory ShareMemory 一个用 C# 实现的 No Sql 数据库 , 也可以说是 分布式 缓存 , ...
- 非root用户执行程序---sudo的使用
场景 在应用部署过程中,会遇到这样的问题:前期需要root用户执行配置.初始化工作,而具体的业务应用需要使用非root用户启动. 如何解决呢? 方法 可以使用sudo,实现授权. sudo命令授权,既 ...
- 查看端口 (windows)
查看端口 netstat -an |findstr
- python findall() re.S
官方文档:https://docs.python.org/3.6/library/re.html 教程:http://www.regexlab.com/zh/regref.htm re.findall ...