详解JavaScript树结构


Posted in Javascript onJanuary 09, 2017

对于数据结构“树”,想必大家都熟悉,今儿,我们就再来回顾一下数据结构中的二叉树与树,并用JavaScript实现它们。

ps:树结构在前端中,很多地方体现得淋漓尽致,如Vue的虚拟DOM以及冒泡等等。

二叉树

--概念--

二叉树是一种树形结构,它的特点是每个结点至多只有两棵子树(即二叉树中不存在度大于2的结点),并且,二叉树的子树有左右之分,其次序不能任意颠倒。

如下,就是一棵二叉树(注:下文二叉树相关例子,都以该二叉树为例):

详解JavaScript树结构

且,遍历二叉树(traversing binary tree)有三种常用方式,如下:

1)、先序遍历二叉树 (根左右)  

        若二叉树为空,则空操作;否则

        --访问根结点;

        --先序遍历左子树;

        --先序遍历右子树。

例如,上述例子中的二叉树,遍历结果如下:

详解JavaScript树结构

2)、中序遍历二叉树(左根右)

         若二叉树为空,则空操作;否则

         --中序遍历左子树;

         --访问根结点;

         --中序遍历右子树。

例如,上述例子中的二叉树,遍历结果如下:

详解JavaScript树结构

3)、后序遍历二叉树(左右根)

        若二叉树为空,则空操作;否则

        --后序遍历左子树;

        --后序遍历右子树;

--访问根结点。

例如,上述例子中的二叉树,遍历结果如下:

详解JavaScript树结构

好了,了解了二叉树以及遍历方式,那么,接下来我们就一起用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)个互不相交的有限集,其中每个集合本身又是一棵树,称为根的子树。当然,二叉树肯定属于树咯。

如下,就是一棵树(注:下文树的相关例子,都以该树为例):

详解JavaScript树结构

且,遍历一棵多孩子树,有两种常用遍历方式,如下:

1) 、先根遍历,和深度优先搜索(Depth_First Search)遍历类似。都是利用栈来遍历元素,如下:

详解JavaScript树结构

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

详解JavaScript树结构

好了,了解了树以及遍历方式,那么,接下来我们就一起用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 相关文章推荐
利用JQuery为搜索栏增加tag提示
Jun 22 Javascript
不同浏览器的怪癖小结
Jul 11 Javascript
jquery的extend和fn.extend的使用说明
Jan 09 Javascript
Jquery工作常用实例 使用AJAX使网页进行异步更新
Jul 26 Javascript
javascript跟随滚动效果插件代码(javascript Follow Plugin)
Aug 03 Javascript
JS实现随机乱撞彩色圆球特效的方法
May 05 Javascript
有关文件上传 非ajax提交 得到后台数据问题
Oct 12 Javascript
angularjs 实现带查找筛选功能的select下拉框实例
Jan 11 Javascript
Angular-Ui-Router+ocLazyLoad动态加载脚本示例
Mar 02 Javascript
深入解析Vue 组件命名那些事
Jul 18 Javascript
详解win7 cmd执行vue不是内部命令的解决方法
Jul 27 Javascript
微信小程序使用map组件实现获取定位城市天气或者指定城市天气数据功能
Jan 22 Javascript
angular分页指令操作
Jan 09 #Javascript
jquery.zclip轻量级复制失效问题
Jan 08 #Javascript
JavaScript & jQuery完美判断图片是否加载完毕
Jan 08 #Javascript
纯javaScript、jQuery实现个性化图片轮播【推荐】
Jan 08 #Javascript
js实现选项卡内容切换以及折叠和展开效果【推荐】
Jan 08 #Javascript
Javascript 实现计算器时间功能详解及实例(二)
Jan 08 #Javascript
JS 实现计算器详解及实例代码(一)
Jan 08 #Javascript
You might like
PHP数组对比函数,存在交集则返回真,否则返回假
2011/02/03 PHP
centos 7.2下搭建LNMP环境教程
2016/11/20 PHP
PHP验证码类ValidateCode解析
2017/01/07 PHP
php生成短网址/短链接原理和用法实例分析
2020/05/29 PHP
一个判断email合法性的函数[非正则]
2008/12/09 Javascript
在JavaScript里嵌入大量字符串常量的实现方法
2013/07/07 Javascript
jQuery循环动画与获取组件尺寸的方法
2015/02/02 Javascript
在JavaScript中正确引用bind方法的应用
2015/05/11 Javascript
jQuery实现百叶窗焦点图动画效果代码分享(附源码下载)
2016/03/14 Javascript
jquery自定义表单验证插件
2016/10/12 Javascript
分享一道关于闭包、bind和this的面试题
2017/02/20 Javascript
node使用UEditor富文本编辑器的方法实例
2017/07/11 Javascript
vue devtools的安装与使用教程
2018/08/08 Javascript
ionic4+angular7+cordova上传图片功能的实例代码
2019/06/19 Javascript
如何在JavaScript中谨慎使用代码注释
2019/06/21 Javascript
微信头像地址失效踩坑记附带解决方案
2019/09/23 Javascript
jQuery轮播图功能制作方法详解
2019/12/03 jQuery
Vue点击切换Class变化,实现Active当前样式操作
2020/07/17 Javascript
[01:35]辉夜杯战队访谈宣传片—LGD
2015/12/25 DOTA
Python实现多线程下载文件的代码实例
2014/06/01 Python
Python 2与Python 3版本和编码的对比
2017/02/14 Python
Python模拟登陆实现代码
2017/06/14 Python
Tornado协程在python2.7如何返回值(实现方法)
2017/06/22 Python
Django如何配置mysql数据库
2018/05/04 Python
Python+numpy实现矩阵的行列扩展方式
2019/11/29 Python
Stuart Weitzman美国官网:美国奢华鞋履品牌
2016/08/18 全球购物
美国糖果店:Sugarfina
2019/02/21 全球购物
体育课课后反思
2014/04/24 职场文书
抗洪救灾先进集体事迹材料
2014/05/26 职场文书
学校运动会报道稿
2014/09/23 职场文书
个人遵守党的政治纪律情况对照检查材料思想汇报
2014/09/25 职场文书
认错检讨书
2014/10/02 职场文书
农业项目合作意向书
2015/05/08 职场文书
中学总务处工作总结
2015/08/12 职场文书
超详细教你怎么升级Mysql的版本
2021/05/19 MySQL
快速学习Oracle触发器和游标
2021/06/30 Oracle