JavaScript实现树结构(一)

一、树结构简介

1.1.简单了解树结构

什么是树?

真实的树:

树的特点:

  • 树一般都有一个,连接着根的是树干
  • 树干会发生分叉,形成许多树枝,树枝会继续分化成更小的树枝
  • 树枝的最后是叶子

现实生活中很多结构都是树的抽象,模拟的树结构相当于旋转180°的树。

树结构对比于数组/链表/哈希表有哪些优势呢:

数组:

  • 优点:可以通过下标值访问,效率高;
  • 缺点:查找数据时需要先对数据进行排序,生成有序数组,才能提高查找效率;并且在插入和删除元素时,需要大量的位移操作

链表:

  • 优点:数据的插入和删除操作效率都很高;
  • 缺点:查找效率低,需要从头开始依次查找,直到找到目标数据为止;当需要在链表中间位置插入或删除数据时,插入或删除的效率都不高。

哈希表:

  • 优点:哈希表的插入/查询/删除效率都非常高;
  • 缺点:空间利用率不高,底层使用的数组中很多单元没有被利用;并且哈希表中的元素是无序的,不能按照固定顺序遍历哈希表中的元素;而且不能快速找出哈希表中最大值或最小值这些特殊值。

树结构:

优点:树结构综合了上述三种结构的优点,同时也弥补了它们存在的缺点(虽然效率不一定都比它们高),比如树结构中数据都是有序的,查找效率高;空间利用率高;并且可以快速获取最大值和最小值等。

总的来说:每种数据结构都有自己特定的应用场景

树结构:

  • 树(Tree):由 n(n ≥ 0)个节点构成的有限集合。当 n = 0 时,称为空树

对于任一棵非空树(n > 0),它具备以下性质:

  • 数中有一个称为根(Root)的特殊节点,用 **r **表示;
  • 其余节点可分为 m(m > 0)个互不相交的有限集合 T1,T2,...,Tm,其中每个集合本身又是一棵树,称为原来树的子树(SubTree)

树的常用术语:

  • 节点的度(Degree):节点的子树个数,比如节点B的度为2;
  • 树的度:树的所有节点中最大的度数,如上图树的度为2;
  • 叶节点(Leaf)度为0的节点(也称为叶子节点),如上图的H,I等;
  • 父节点(Parent):度不为0的节点称为父节点,如上图节点B是节点D和E的父节点;
  • 子节点(Child):若B是D的父节点,那么D就是B的子节点;
  • 兄弟节点(Sibling):具有同一父节点的各节点彼此是兄弟节点,比如上图的B和C,D和E互为兄弟节点;
  • 路径和路径长度:路径指的是一个节点到另一节点的通道,路径所包含边的个数称为路径长度,比如A->H的路径长度为3;
  • 节点的层次(Level):规定根节点在1层,其他任一节点的层数是其父节点的层数加1。如B和C节点的层次为2;
  • 树的深度(Depth):树种所有节点中的最大层次是这棵树的深度,如上图树的深度为4;

1.2.树结构的表示方式

  • 最普通的表示方法

如图,树结构的组成方式类似于链表,都是由一个个节点连接构成。不过,根据每个父节点子节点数量的不同,每一个父节点需要的引用数量也不同。比如节点A需要3个引用,分别指向子节点B,C,D;B节点需要2个引用,分别指向子节点E和F;K节点由于没有子节点,所以不需要引用。

这种方法缺点在于我们无法确定某一结点的引用数。

  • 儿子-兄弟表示法

这种表示方法可以完整地记录每个节点的数据,比如:

//节点A
Node{
//存储数据
this.data = data
//统一只记录左边的子节点
this.leftChild = B
//统一只记录右边的第一个兄弟节点
this.rightSibling = null
} //节点B
Node{
this.data = data
this.leftChild = E
this.rightSibling = C
} //节点F
Node{
this.data = data
this.leftChild = null
this.rightSibling = null
}

这种表示法的优点在于每一个节点中引用的数量都是确定的。

  • 儿子-兄弟表示法旋转

以下为儿子-兄弟表示法组成的树结构:

将其顺时针旋转45°之后:

这样就成为了一棵二叉树,由此我们可以得出结论:任何树都可以通过二叉树进行模拟。但是这样父节点不是变了吗?其实,父节点的设置只是为了方便指向子节点,在代码实现中谁是父节点并没有关系,只要能正确找到对应节点即可。

二、二叉树

2.1.二叉树简介

二叉树的概念:如果树中的每一个节点最多只能由两个子节点,这样的树就称为二叉树

二叉树十分重要,不仅仅是因为简单,更是因为几乎所有的树都可以表示成二叉树形式。

二叉树的组成

  • 二叉树可以为空,也就是没有节点;
  • 若二叉树不为空,则它由根节点和称为其左子树TL和右子树TR的两个不相交的二叉树组成;

二叉树的五种形态

上图分别表示:空的二叉树、只有一个节点的二叉树、只有左子树TL的二叉树、只有右子树TR的二叉树和有左右两个子树的二叉树。

二叉树的特性

  • 一个二叉树的第 i 层的最大节点树为:2(i-1),i >= 1;
  • 深度为k的二叉树的最大节点总数为:2k - 1 ,k >= 1;
  • 对任何非空二叉树,若 n0 表示叶子节点的个数,n2表示度为2的非叶子节点个数,那么两者满足关系:n0 = n2 + 1;如下图所示:H,E,I,J,G为叶子节点,总数为5;A,B,C,F为度为2的非叶子节点,总数为4;满足n0 = n2 + 1的规律。

2.2.特殊的二叉树

完美二叉树

完美二叉树(Perfect Binary Tree)也成为满二叉树(Full Binary Tree),在二叉树中,除了最下一层的叶子节点外,每层节点都有2个子节点,这就构成了完美二叉树。

完全二叉树

完全二叉树(Complete Binary Tree):

  • 除了二叉树最后一层外,其他各层的节点数都达到了最大值;
  • 并且,最后一层的叶子节点从左向右是连续存在,只缺失右侧若干叶子节点;
  • 完美二叉树是特殊的完全二叉树;

在上图中,由于H缺失了右子节点,所以它不是完全二叉树。

2.3.二叉树的数据存储

常见的二叉树存储方式为数组链表

使用数组:

  • 完全二叉树:按从上到下,从左到右的方式存储数据。

节点 A B C D E F G H
序号 1 2 3 4 5 6 7 8

使用数组存储时,取数据的时候也十分方便:左子节点的序号等于父节点序号 * 2,右子节点的序号等于父节点序号 * 2 + 1 。

  • 非完全二叉树:非完全二叉树需要转换成完全二叉树才能按照上面的方案存储,这样会浪费很大的存储空间。

节点 A B C ^ ^ F ^ ^ ^ ^ ^ ^ M
序号 1 2 3 4 5 6 7 8 9 10 11 12 13

使用链表

二叉树最常见的存储方式为链表:每一个节点封装成一个Node,Node中包含存储的数据、左节点的引用和右节点的引用。

三、二叉搜索树

3.1.认识二叉搜索树

二叉搜索树BST,Binary Search Tree),也称为二叉排序树二叉查找树

二叉搜索树是一棵二叉树,可以为空;

如果不为空,则满足以下性质

  • 条件1:非空左子树的所有键值小于其根节点的键值。比如三中节点6的所有非空左子树的键值都小于6;
  • 条件2:非空右子树的所有键值大于其根节点的键值;比如三中节点6的所有非空右子树的键值都大于6;
  • 条件3:左、右子树本身也都是二叉搜索树;

如上图所示,树二和树三符合3个条件属于二叉树,树一不满足条件3所以不是二叉树。

总结:二叉搜索树的特点主要是较小的值总是保存在左节点上,相对较大的值总是保存在右节点上。这种特点使得二叉搜索树的查询效率非常高,这也就是二叉搜索树中"搜索"的来源。

3.2.二叉搜索树应用举例

下面是一个二叉搜索树:

若想在其中查找数据10,只需要查找4次,查找效率非常高。

  • 第1次:将10与根节点9进行比较,由于10 > 9,所以10下一步与根节点9的右子节点13比较;
  • 第2次:由于10 < 13,所以10下一步与父节点13的左子节点11比较;
  • 第3次:由于10 < 11,所以10下一步与父节点11的左子节点10比较;
  • 第4次:由于10 = 10,最终查找到数据10 。

同样是15个数据,在排序好的数组中查询数据10,需要查询10次:

其实:如果是排序好的数组,可以通过二分查找:第一次找9,第二次找13,第三次找15...。我们发现如果把每次二分的数据拿出来以树的形式表示的话就是二叉搜索树。这就是数组二分法查找效率之所以高的原因。

参考资料:JavaScript数据结构与算法

JavaScript实现树结构(一)的更多相关文章

  1. JavaScript实现树结构(二)

    JavaScript实现树结构(二) 一.二叉搜索树的封装 二叉树搜索树的基本属性: 如图所示:二叉搜索树有四个最基本的属性:指向节点的根(root),节点中的键(key).左指针(right).右指 ...

  2. JavaScript遍历树结构

    遍历 function parseTreeJson(treeNodes){ if(!treeNodes||!treeNodes.length)return; for(let i=0;i<tree ...

  3. 树结构之JavaScript

    对于数据结构“树”,想必大家都熟悉,今儿,我们就再来回顾一下数据结构中的二叉树与树,并用JavaScript实现它们. ps:树结构在前端中,很多地方体现得淋漓尽致,如Vue的虚拟DOM以及冒泡等等. ...

  4. 用JavaScript实现一个简单的树结构

    数据源用数组混json结构,实现了基本的功能.效率一般,跟 dhtree 梅花雪树对比了下,都差不多. (ps感觉比dhtree快点,跟梅花雪树差不多,个人测试) 这个实现树的原理是根据json,不断 ...

  5. JavaScript 将行结构数据转化为树结构数据源(高效转化方案)

    js接收到后台的数据如下 /// 部门信息 var departRows = [{ parentDepartId: 'root', departId: 'DC', departName: '集团' } ...

  6. react+redux教程(五)异步、单一state树结构、componentWillReceiveProps

    今天,我们要讲解的是异步.单一state树结构.componentWillReceiveProps这三个知识点. 例子 这个例子是官方的例子,主要是从Reddit中请求新闻列表来显示,可以切换reac ...

  7. javascript性能优化-repaint和reflow

    repaint(重绘) ,repaint发生更改时,元素的外观被改变,且在没有改变布局的情况下发生,如改变outline,visibility,background color,不会影响到dom结构渲 ...

  8. javascript 杂记

    博客 http://www.cnblogs.com/onepixel/ http://www.cnblogs.com/ahthw/p/4240220.html#javascript call.appl ...

  9. JavaScript进阶知识点(慕课)

    JavaScript能做什么? 1.增强页面动态效果(如:下拉菜单.图片轮播.信息滚动等) 2.实现页面与用户之间的实时.动态交互(如:用户注册.登陆验证等)  一. 数组 var myarray=n ...

随机推荐

  1. 电脑莫名重启,VS代码丢失的解决办法

    今天写了一天的代码,然后电脑放在公司了,出去看电影(公司组织红色文化培训..)回来发现电脑重启,再打开电脑,VS的代码都不见了.好慌.... 别慌处理办法来了: 打开everything(没有的可以下 ...

  2. VBA引用管理工具(可用于32、64位Office,Win7 Win10均可)

    VBAReferenceManager安装和使用方法,操作请看动态图: 下载地址: VBAReferenceManager.zip

  3. html,将元素水平,垂直居中的四种方式

    将元素垂直,水平居中分两种情况:一个是元素尺寸固定,二是元素尺寸不固定 一.尺寸固定 方法1:定位 ,50%,margin负距 .box{ width: 400px; height: 300px; b ...

  4. HihoCode-1323-回文字符串

    参考博客: https://blog.csdn.net/mitsuha_/article/details/76690634 https://blog.csdn.net/u014142379/artic ...

  5. [LC] 62. Unique Paths

    A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The ...

  6. Qt char * 与 const char * 的转换

    char *ch1="hello11"; const char *ch2="hello22"; ch2 = ch1;//不报错,但有警告 ch1 = (char ...

  7. 瑞星发布Linux系统安全报告:Linux病毒或将大面积爆发

    近半年来,由于中央推荐使用国产Linux操作系统,国产Linux操作系统开始受到政府机关及大型企事业机关单位的高度重视.很多人都认为,以Linux系统为基础的国产操作系统最符合国家.政府和企业信息安全 ...

  8. idea 内存溢出解决方法

    在Run/Debug configuration 的 vm options里面输入 -server -XX:PermSize=128M -XX:MaxPermSize=256m 具体如下图:

  9. Angular2与Angular1的区别

    原文地址: http://www.angularjs.cn/A2Ar 整体上来说,Angular2变得更加简洁,最核心的概念只剩下一个,那就是组件Component,其它所有的一切都是围绕着Compo ...

  10. AFNetworking基本模块

    AFNetworking主要分为5个模块 通信模块(AFURLSessionManager, AFHTTPSessionManager) 网络状态监听 安全模块 通信序列化/反序列化模块 UIKit相 ...