详解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 获得服务器控件值的方法小结
May 11 Javascript
鼠标右击事件代码(asp.net后台)
Jan 27 Javascript
js实现页面跳转重定向的几种方式
May 29 Javascript
jQuery中andSelf()方法用法实例
Jan 08 Javascript
原生javascript实现Tab选项卡切换功能
Jan 12 Javascript
jQuery动态星级评分效果实现方法
Aug 06 Javascript
vue实现可增删查改的成绩单
Oct 27 Javascript
JS实现获取进今年第几天是周几的方法分析
Jun 27 Javascript
Vue无限滑动周选择日期的组件的示例代码
Jul 18 Javascript
微信小程序云开发之新手环境配置
May 16 Javascript
vue学习之Vue-Router用法实例分析
Jan 06 Javascript
在vue中axios设置timeout超时的操作
Sep 04 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
建立动态的WML站点(一)
2006/10/09 PHP
adodb与adodb_lite之比较
2006/12/31 PHP
用phpmyadmin更改mysql5.0登录密码
2008/03/25 PHP
用PHP程序实现支持页面后退的两种方法
2008/06/30 PHP
并发下常见的加锁及锁的PHP具体实现代码
2010/10/12 PHP
setcookie中Cannot modify header information-headers already sent by错误的解决方法详解
2013/05/08 PHP
PHP实现通过中文字符比率来判断垃圾评论的方法
2014/10/20 PHP
php使用CURL不依赖COOKIEJAR获取COOKIE的方法
2015/06/17 PHP
帝国CMS留言板回复后发送EMAIL通知客户
2015/07/06 PHP
Wordpress ThickBox 点击图片显示下一张图的修改方法
2010/12/11 Javascript
Js 导出table内容到Excel的简单实例
2013/11/19 Javascript
JS 打印界面的CSS居中代码适用所有浏览器
2014/03/19 Javascript
本地Bootstrap文件字体图标引入却无法显示问题的解决方法
2020/04/18 Javascript
Angularjs自定义指令实现三级联动 选择地理位置
2017/02/13 Javascript
JS声明对象时属性名加引号与不加引号的问题及解决方法
2018/02/16 Javascript
使用vue打包进行云服务器上传的问题
2020/03/02 Javascript
jquery.validate自定义验证用法实例分析【成功提示与择要提示】
2020/06/06 jQuery
vue深度监听(监听对象和数组的改变)与立即执行监听实例
2020/09/04 Javascript
如何编写一个 Webpack Loader的实现
2020/10/18 Javascript
[36:14]DOTA2上海特级锦标赛D组小组赛#1 EG VS COL第二局
2016/02/28 DOTA
python求pi的方法
2014/10/08 Python
python实现提取百度搜索结果的方法
2015/05/19 Python
玩转python爬虫之URLError异常处理
2016/02/17 Python
Python三级菜单的实例
2017/09/13 Python
python 将日期戳(五位数时间)转换为标准时间
2019/07/11 Python
Python函数中的可变长参数详解
2019/09/12 Python
python如何获取apk的packagename和activity
2020/01/10 Python
pycharm 2018 激活码及破解补丁激活方式
2020/09/21 Python
通过Django Admin+HttpRunner1.5.6实现简易接口测试平台
2020/11/11 Python
Trunki英国官网:儿童坐骑式行李箱
2017/05/30 全球购物
Viking Direct荷兰:购买办公用品
2019/06/20 全球购物
PHP如何与mysql建立链接
2013/05/05 面试题
Java中的异常处理机制的简单原理和应用
2013/04/27 面试题
商务英语专业求职信范文
2014/01/28 职场文书
将Python代码打包成.exe可执行文件的完整步骤
2021/05/12 Python
Python用tkinter实现自定义记事本的方法详解
2022/03/31 Python