JavaScript 数据结构与算法之美 - 非线性表中的树、堆是干嘛用的 ?其数据结构是怎样的 ?(上)

简介: JavaScript 数据结构与算法之美 - 非线性表中的树、堆是干嘛用的 ?其数据结构是怎样的 ?(上)

1. 前言


想学好前端,先练好内功,内功不行,就算招式练的再花哨,终究成不了高手。

非线性表(树、堆),可以说是前端程序员的内功,要知其然,知其所以然。


笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 JavaScript ,旨在入门数据结构与算法和方便以后复习。


非线性表中的树、堆是干嘛用的 ?其数据结构是怎样的 ?


希望大家带着这两个问题阅读下文。


2. 树


微信图片_20220513105643.png


的数据结构就像我们生活中的真实的树,只不过是倒过来的形状。


术语定义


  • 节点:树中的每个元素称为节点,如 A、B、C、D、E、F、G、H、I、J。
  • 父节点:指向子节点的节点,如 A。
  • 子节点:被父节点指向的节点,如 A 的孩子 B、C、D。
  • 父子关系:相邻两节点的连线,称为父子关系,如 A 与 B,C 与 H,D 与 J。
  • 根节点:没有父节点的节点,如 A。
  • 叶子节点:没有子节点的节点,如 E、F、G、H、I、J。
  • 兄弟节点:具有相同父节点的多个节点称为兄弟节点,如 B、C、D。
  • 节点的高度:节点到叶子节点的最长路径所包含的边数。
  • 节点的深度:根节点到节点的路径所包含的边数。
  • 节点层数:节点的深度 +1(根节点的层数是 1 )。
  • 树的高度:等于根节点的高度。
  • 森林: n 棵互不相交的树的集合。


微信图片_20220513105700.png


高度是从下往上度量,比如一个人的身高 180cm ,起点就是从 0 开始的。


深度是从上往下度量,比如泳池的深度 180cm ,起点也是从 0 开始的。


高度和深度是带有字的,都是从 0 开始计数的。


而层数的计算,是和我们平时的楼层的计算是一样的,最底下那层是第 1 层,是从 1 开始计数的,所以根节点位于第 1 层,其他子节点依次加 1。


二叉树分类


微信图片_20220513105721.png


二叉树


  • 每个节点最多只有 2 个子节点的树,这两个节点分别是左子节点和右子节点。如上图中的 1、 2、3。


不过,二叉树并不要求每个节点都有两个子节点,有的节点只有左子节点,有的节点只有右子节点。以此类推,自己想四叉树、八叉树的结构图。


满二叉树


  • 一种特殊的二叉树,除了叶子节点外,每个节点都有左右两个子节点,这种二叉树叫做满二叉树。如上图中的 2。

完全二叉树


  • 一种特殊的二叉树,叶子节点都在最底下两层,最后一层叶子节都靠排列,并且除了最后一层,其他层的节点个数都要达到最大,这种二叉树叫做完全二叉树。如上图的 3。


完全二叉树与不是完全二叉树的区分比较难,所以对比下图看看。


微信图片_20220513105743.png



之前的文章 栈内存与堆内存 、浅拷贝与深拷贝 中有说到:JavaScript 中的引用类型(如对象、数组、函数等)是保存在堆内存中的对象,值大小不固定,栈内存中存放的该对象的访问地址指向堆内存中的对象,JavaScript 不允许直接访问堆内存中的位置,因此操作对象时,实际操作对象的引用。


那么到底是什么呢 ?其数据结构又是怎样的呢 ?


堆其实是一种特殊的树。只要满足这两点,它就是一个堆。


  • 堆是一个完全二叉树。


完全二叉树:除了最后一层,其他层的节点个数都是满的,最后一层的节点都靠左排列。


  • 堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。

也可以说:堆中每个节点的值都大于等于(或者小于等于)其左右子节点的值。这两种表述是等价的。


对于每个节点的值都大于等于子树中每个节点值的堆,我们叫作大顶堆。对于每个节点的值都小于等于子树中每个节点值的堆,我们叫作小顶堆


微信图片_20220513105816.png


其中图 1 和 图 2 是大顶堆,图 3 是小顶堆,图 4 不是堆。除此之外,从图中还可以看出来,对于同一组数据,我们可以构建多种不同形态的堆。


二叉查找树(Binary Search Tree)


  • 一种特殊的二叉树,相对较小的值保存在左节点中,较大的值保存在右节点中,叫二叉查找树,也叫二叉搜索树。


二叉查找树是一种有序的树,所以支持快速查找、快速插入、删除一个数据。

下图中, 3 个都是二叉查找树,


微信图片_20220513105835.png


平衡二叉查找树


  • 平衡二叉查找树:二叉树中任意一个节点的左右子树的高度相差不能大于 1

从这个定义来看,完全二叉树、满二叉树其实都是平衡二叉树,但是非完全二叉树也有可能是平衡二叉树。


平衡二叉查找树中平衡的意思,其实就是让整棵树左右看起来比较对称、比较平衡,不要出现左子树很高、右子树很矮的情况。这样就能让整棵树的高度相对来说低一些,相应的插入、删除、查找等操作的效率高一些。


平衡二叉查找树其实有很多,比如,Splay Tree(伸展树)、Treap(树堆)等,但是我们提到平衡二叉查找树,听到的基本都是红黑树。


微信图片_20220513105851.png


红黑树(Red-Black Tree)


红黑树中的节点,一类被标记为黑色,一类被标记为红色。除此之外,一棵红黑树还需要满足这样几个要求:


  • 根节点是黑色的。
  • 每个叶子节点都是黑色的空节点(NIL),也就是说,叶子节点不存储数据。
  • 任何相邻的节点都不能同时为红色,也就是说,红色节点是被黑色节点隔开的。
  • 每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点。

下面两个都是红黑树。


微信图片_20220513105905.png


存储


完全二叉树的存储


  • 链式存储


每个节点由 3 个字段,其中一个存储数据,另外两个是指向左右子节点的指针。

我们只要拎住根节点,就可以通过左右子节点的指针,把整棵树都串起来。

这种存储方式比较常用,大部分二叉树代码都是通过这种方式实现的。


微信图片_20220513105919.png


  • 顺序存储


用数组来存储,对于完全二叉树,如果节点 X 存储在数组中的下标为 i ,那么它的左子节点的存储下标为 2 i ,右子节点的下标为 2 i + 1,反过来,下标 i / 2 位置存储的就是该节点的父节点。


注意,根节点存储在下标为 1 的位置。完全二叉树用数组来存储是最省内存的方式。


微信图片_20220513105940.png

相关文章
|
11月前
|
机器学习/深度学习 传感器 算法
【无人车路径跟踪】基于神经网络的数据驱动迭代学习控制(ILC)算法,用于具有未知模型和重复任务的非线性单输入单输出(SISO)离散时间系统的无人车的路径跟踪(Matlab代码实现)
【无人车路径跟踪】基于神经网络的数据驱动迭代学习控制(ILC)算法,用于具有未知模型和重复任务的非线性单输入单输出(SISO)离散时间系统的无人车的路径跟踪(Matlab代码实现)
660 2
|
Web App开发 数据采集 JavaScript
动态网页爬取:Python如何获取JS加载的数据?
动态网页爬取:Python如何获取JS加载的数据?
1960 58
|
12月前
|
传感器 算法 Python
【电机矢量控制算法】基于线性死区补偿的永磁同步电机矢量控制算法仿真
【电机矢量控制算法】基于线性死区补偿的永磁同步电机矢量控制算法仿真
323 3
|
算法
数据结构之博弈树搜索(深度优先搜索)
本文介绍了使用深度优先搜索(DFS)算法在二叉树中执行遍历及构建链表的过程。首先定义了二叉树节点`TreeNode`和链表节点`ListNode`的结构体。通过递归函数`dfs`实现了二叉树的深度优先遍历,按预序(根、左、右)输出节点值。接着,通过`buildLinkedList`函数根据DFS遍历的顺序构建了一个单链表,展示了如何将树结构转换为线性结构。最后,讨论了此算法的优点,如实现简单和内存效率高,同时也指出了潜在的内存管理问题,并分析了算法的时间复杂度。
585 0
|
12月前
|
机器学习/深度学习 人工智能 算法
【多智能体编队】基于自适应控制算法非线性输入的多智能体系统编队控制研究(Matlab代码复现)
【多智能体编队】基于自适应控制算法非线性输入的多智能体系统编队控制研究(Matlab代码复现)
295 0
|
机器学习/深度学习 算法 数据格式
MARS算法理论和Python代码实现:用分段回归解决非线性时间序列预测问题
本文将深入探讨MARS算法的核心原理,并详细阐述其在时间序列预测任务中的应用策略与技术实现。
569 0
|
算法 Java
算法系列之数据结构-Huffman树
Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
509 3
 算法系列之数据结构-Huffman树
|
存储 自然语言处理 数据库
【数据结构进阶】AVL树深度剖析 + 实现(附源码)
在深入探讨了AVL树的原理和实现后,我们不难发现,这种数据结构不仅优雅地解决了传统二叉搜索树可能面临的性能退化问题,还通过其独特的平衡机制,确保了在任何情况下都能提供稳定且高效的查找、插入和删除操作。
1015 19
|
存储 C++
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
【数据结构——树】哈夫曼树(头歌实践教学平台习题)【合集】目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果:任务描述 本关任务:编写一个程序构建哈夫曼树和生成哈夫曼编码。 相关知识 为了完成本关任务,你需要掌握: 1.如何构建哈夫曼树, 2.如何生成哈夫曼编码。 测试说明 平台会对你编写的代码进行测试: 测试输入: 1192677541518462450242195190181174157138124123 (用户分别输入所列单词的频度) 预
668 14
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
613 12