文章目录
近期文章:
- Vue3开发常见性能问题知多少
- Vue3组件常见通信方式你了解多少?
- 实现篇:LRU算法的几种实现
- 从底层视角看requestAnimationFrame的性能增强
- Nginx Upstream了解一下
- 实现篇:一文搞懂Promise是如何实现的
- 实现篇:如何手动实现JSON.parse
- 实现篇:如何亲手定制实现JSON.stringify
- 一文搞懂 Markdown 文档规则
二叉树是一种树形数据结构,每个节点最多有两个子节点,分别称为左子节点和右子节点。在文件存储、金融决策、语言编译、数据压缩等方面广泛应用。
其二叉树遍历是一个常见场景:深度优先遍历(DFS) 和 广度优先遍历(BFS)。其中深度遍历又常有三种遍历方式:前序遍历、中序遍历、后序遍历。以下就分别通过javascript语言总结实现这些常见遍历方式。
- 节点结构:
function TreeNode(value) {
this.value = value;
this.left = this.right = null;
}
- 测试用例请到文章最后查看,完整示例代码:js-code/BinaryTree
1 前序遍历
前序遍历顺序:根节点 → 左子树 → 右子树
1.1 递归实现
递归是最直观的方式,直接按照前序的定义顺序处理节点:
- 代码简洁,直接映射前序逻辑。
- 缺点:递归深度过大时可能导致栈溢出,适用于树深度较小的场景。
function preorder(root) {
const result = []
const loop = (node) => {
if (node === null) return
result.push(node.value)
if (node.left !== null) loop(node.left)
if (node.right !== null) loop(node.right)
}
loop(root)
return result
}
1.2 迭代实现
通过栈模拟递归过程,避免栈溢出风险,适合处理大型树结构:
1.2.1 单栈法
- 栈的入栈顺序为“右→左”,保证出栈顺序为“根→左→右”。
- 时间复杂度:O(n),空间复杂度:O(n)。
function loopPreorder(root) {
const result = []
if (root === null) return result
const stack = [root]
while(stack.length) {
const node = stack.pop()
result.push(node.value)
if (node.right !== null) stack.push(node.right)
if (node.left !== null) stack.push(node.left)
}
return result
}
1.2.2 统一迭代法
通过标记法统一前、中、后序遍历的迭代逻辑。逻辑统一,但需要额外处理节点标记,适用于需要灵活切换遍历方式的场景。
function loopPreorder2(root) {
const stack = [root], result = [];
while (stack.length) {
const node = stack.pop();
// 双等号判断包括null和undefined
if (node == null) <