数据结构二叉树分享讲
目录
- 摘要:
- 二叉树由来
- 为什么要有二叉树
- 二叉树树结构的重点概念
- 二叉树存储
- 二叉树遍历的时间复杂度,空间复杂度
- 递归树-分析思路
- 二叉树的优势运用
- 树的运用场景
- 前端领域
- 二叉树的弊端
- 树本身的局限性呢
摘要:
二叉树是计算机科学中的一种重要数据结构,它是一种树状结构,其中每个节点最多有两个子节点。二叉树在许多场景中具有优势,但也有一些局限性。本文将介绍二叉树的基本概念、由来、为什么需要二叉树以及二叉树在前端领域的应用。
二叉树由来
- 在 20 世纪 60 年代,计算机科学家们开始研究二叉树及其相关算法。1960 年代初,计算机科学家 Edsger Dijkstra 发表了关于二叉树的早期研究,提出了一种基于二叉树的堆(Heap)数据结构。1964 年,计算机科学家 George J. Collins 提出了 AVL 树,这是一种自平衡的二叉搜索树。这些早期的研究为后来的二叉树算法和应用奠定了基础。
为什么要有二叉树
主要是为了解决数据组织存储(树可以存储具备层次关系的数据)和检索效率的问题(检索效率:以二插搜索为例子:每次一分为二,时间复杂度O(logn),而线性表查询o(n),
二叉树树结构的重点概念
- 高度从下往上
- 深度:从海平面向下
- 完全二叉树:除过最后一层,所有叶子节点都是满的,并且叶子节点从左到到友连续,用数组存储无空洞
- 满二叉树就是完全对称的完全二叉树。
二叉树存储
- 一个是可以通过数组来存储,另一个是通过链表。
- 什么时候适合用数组:当树为完全二叉树,这样不会出现数组空洞
二叉树遍历的时间复杂度,空间复杂度
当人们谈论树的高度为 logn 时,他们通常是指理想情况下的平衡二叉树。在平衡二叉树中,每个节点最多有两个子节点,而且每一层的节点数都是上一层节点数的两倍。对于这样的树,高度与节点数量之间存在对数关系。
在平衡二叉树中,假设有 n 个节点,树的高度为 h。根据每层节点数的规律,我们可以得到以下关系:
n = 1 + 2 + 4 + ... + 2^h
这是一个等比数列求和公式,可以简化为:
n = 2^(h+1) - 1
为了求解 h,我们可以对上式取对数(以 2 为底):
h + 1 = log2(n + 1)
h = log2(n + 1) - 1
二叉树遍历,每个节点最多两次时间复杂度为O(n),对于当前 整个树的存储,空间复杂度为 O(n),某一层的空间复杂度为O(logN)
递归树-分析思路
- 第一步有几层,第二步,每层耗时,总高度为h 更具之前的计算整体的高度 logN 每层有总共的合并时间为N所以为Ologn. 总计算:h*n
- 快排的递归树:为什么一定不能为一颗斜树。会达到O(n^2);
二叉树的优势运用
树的运用场景
- 有序性:二叉搜索树(BST)是一种特殊的二叉树,其节点的左子树上所有节点的值都小于根节点,而右子树上所有节点的值都大于根节点。这种有序性使得二叉搜索树非常适用于需要进行查找、插入和删除操作的场景
- 平衡性:自平衡二叉搜索树(例如 AVL 树和红黑树)在插入和删除操作时会自动调整,以保持树的高度最小。这使得操作的时间复杂度始终保持在 O(log n) 级别。这种平衡性使得自平衡二叉搜索树在需要高性能的场景下非常有用,因为如果随着操作,最坏的情况可能退化成一个链表。
- 高效的遍历:叉树可以进行多种遍历方式,如前序、中序、后序和层次遍历。这使得二叉树在需要对数据进行遍历和处理的场景下非常有用。例如,在编译器和解释器中,抽象语法树(AST) 通常采用二叉树或多叉树表示,遍历过程中可以进行语法检查、代码优化等操作,其他结构由于很难描述事物之间的层级关系,所以就是要用二叉或多叉树的结构
- 堆:堆本质上是一个完全二叉树,所以存储用数组就很高效,用于实现优先队列。在需要维护最大值/最小值的场景下,二叉堆可以提供 O(log n) 的插入和删除操作,联系之前的求前K大数。
二叉搜索的运用
- 定义
- 左子树比根节点小,右子树比根节点大
- 时间查找复杂度类似二分思想:因此时间复杂度 O(logN),相比于数组,链表o(n)查询要快,比哈希表空间复杂度低
- 适用范围二叉搜索树适用于需要高效查找、插入、删除、排序和范围查询的场景
- 优势弊端:1. 如果树不平衡会退化为链表,
前端领域
- DOM(Document Object Model)树:在 Web 开发中,网页的结构通常表示为 DOM 树,其中每个节点代表一个 HTML 元素
- 虚拟 DOM(Virtual DOM)树:在现代前端框架(如 React 和 Vue)中,虚拟 DOM 树作为一种轻量级的 DOM 表示,用于提高页面渲染性能。
- Fiber节点
举例子:
- `type`:组件的类型,如函数组件、类组件等。
- `stateNode`:组件实例的引用,如 DOM 节点或类组件实例。
- `child`:指向第一个子节点的引用。
- `sibling`:指向下一个兄弟节点的引用。
- `return`:指向父节点的引用。
// 指向父级Fiber节点
this.return = null;
// 指向子Fiber节点
this.child = null;
// 指向右边第一个兄弟Fiber节点
this.sibling = null;
function App() {
return (
<div>
i am
<span>KaSong</span>
</div>
)
}
之所以一定要用树,是因为组件本身就是呈现为树状结构,存在父子,兄弟的层层关系。
二叉树的弊端
大量重复数据:如果数据集中存在大量重复数据,二叉搜索树可能不是最佳选择
需要频繁更新数据的场景下,二叉树可能不是最佳选择,因为更新操作可能导致树的结构变得不平衡。
无序数据集:如果数据集无序且无需排序,二叉搜索树的优势可能无法体现
树本身的局限性呢
- 线性数据结构:如果数据是线性的,且不需要表示层次关系或复杂的排序,那么使用链表或数组可能更为简单和高效
- 树结构通常更适合处理动态变化的数据集。
- 单查找和更新:对于简单的查找、插入和删除操作,使用哈希表可能更为高效因为是O(1).