计算机的数据结构是对现实世界物体间关系的一种抽象。比如家族的族谱,公司架构中的人员组织关系,电脑中的文件夹结构,HTML 渲染的 DOM 结构等等,这些有层次关系的结构在计算机领域都叫做树。
比较规范的来说,树是一种非线性数据结构。树结构的基本单位是节点。节点之间的链接,称为分支(branch)。节点与分支形成树状,结构的开端,称为根(root),或根结点。根节点之外的节点,称为子节点(child)。没有链接到其他子节点的节点,称为叶节点(leaf)。如下图是一个典型的树结构:
树的节点数据结构一般为:
interface Node {
value: any; // 当前节点的值
children: Array<Node>; // 指向子
}
其他重要概念:
- 树的高度:节点到叶子节点的最大值就是其高度。
- 树的深度:高度和深度是相反的,高度是从下往上数,深度是从上往下。因此根节点的深度和叶子节点的高度是 0。
- 树的层:根开始定义,根为第一层,根的孩子为第二层。
二叉树是树结构的一种,「二叉」就是说每个节点最多只有两个子节点,我们习惯称之为左节点和右节点,它的节点数据结构一般为:
interface Node {
value: any; // 当前节点的值
left: Node; // 指向左节点
right: Node; // 指向右节点
}
- 完全二叉树
- 满二叉树
- 二叉搜索树
- 平衡二叉树
- 红黑树 。。。
- 链表存储
- 数组存储。非常适合完全二叉树
所有跟树有关的题目只有一个中心点,那就是树的遍历,不会树的遍历一切都是百搭。
但是如何遍历呢?首先毫无疑问的是必须得从根节点开始访问,然后根据子节点指针访问子节点,但是子节点有多个(二叉树最多两个)方向,所以又有了先访问哪个的问题,这造成了不同的遍历方式。
遍历是为了什么呢?一般是查找搜索、修改节点内容,移动、删除以及交换节点等等。树虽然只能从根开始访问,但是我们可以选择在访问完毕回来的时候做处理,还是在访问回来之前做处理,这两种不同的方式就是后序遍历和先序遍历。
而树的遍历又可以分为两个基本类型,分别是深度优先遍历(Depth-First-Search,DFS)和广度优先遍历(Breadth-First Search,BFS)。像二叉树的前中后序遍历的递归实现都属于深度优先遍历,用栈迭代的方式就属于广度优先遍历。