多叉树的递归/层序遍历

简介: 多叉树是二叉树的扩展,每个节点可有多个子节点。遍历方式类似:递归实现DFS时无中序概念;层序遍历(BFS)用队列处理,支持记录深度与权重,代码结构清晰统一。

一句话总结
多叉树结构就是 二叉树结构 的延伸,二叉树是特殊的多叉树。森林是指多个多叉树的集合。
多叉树的遍历就是 二叉树遍历 的延伸。
二叉树的节点长这样,每个节点有两个子节点:
class TreeNode {
int val;
TreeNode left;
TreeNode right;
}
多叉树的节点长这样,每个节点有任意个子节点:
class Node {
int val;
List children;
}
就这点区别,其他没了。
递归遍历(DFS)
对比二叉树的遍历框架看多叉树的遍历框架吧:
// 二叉树的遍历框架
void traverse(TreeNode root) {
if (root == null) {
return;
}
// 前序位置
traverse(root.left);
// 中序位置
traverse(root.right);
// 后序位置
}

// N 叉树的遍历框架
void traverse(Node root) {
if (root == null) {
return;
}
// 前序位置
for (Node child : root.children) {
traverse(child);
}
// 后序位置
}
唯一的区别是,多叉树没有了中序位置,因为可能有多个节点嘛,所谓的中序位置也就没什么意义了。
层序遍历(BFS)
多叉树的层序遍历和 二叉树的层序遍历 一样,都是用队列来实现,无非就是把二叉树的左右子节点换成了多叉树的所有子节点。所以多叉树的层序遍历也有三种写法,下面一一列举。
写法一
第一种层序遍历写法:
void levelOrderTraverse(Node root) {
if (root == null) {
return;
}
Queue q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
Node cur = q.poll();
// 访问 cur 节点
System.out.println(cur.val);

    // 把 cur 的所有子节点加入队列
    for (Node child : cur.children) {
        q.offer(child);
    }
}

}
写法二
第二种能够记录节点深度的层序遍历写法:
void levelOrderTraverse(Node root) {
if (root == null) {
return;
}
Queue q = new LinkedList<>();
q.offer(root);
// 记录当前遍历到的层数(根节点视为第 1 层)
int depth = 1;

while (!q.isEmpty()) {
    int sz = q.size();
    for (int i = 0; i < sz; i++) {
        Node cur = q.poll();
        // 访问 cur 节点,同时知道它所在的层数
        System.out.println("depth = " + depth + ", val = " + cur.val);

        for (Node child : cur.children) {
            q.offer(child);
        }
    }
    depth++;
}

}
写法三
第三种能够适配不同权重边的写法:
class State {
Node node;
int depth;

public State(Node node, int depth) {
    this.node = node;
    this.depth = depth;
}

}

void levelOrderTraverse(Node root) {
if (root == null) {
return;
}
Queue q = new LinkedList<>();
// 记录当前遍历到的层数(根节点视为第 1 层)
q.offer(new State(root, 1));

while (!q.isEmpty()) {
    State state = q.poll();
    Node cur = state.node;
    int depth = state.depth;
    // 访问 cur 节点,同时知道它所在的层数
    System.out.println("depth = " + depth + ", val = " + cur.val);

    for (Node child : cur.children) {
        q.offer(new State(child, depth + 1));
    }
}

}

相关文章
|
20小时前
|
机器学习/深度学习 人工智能 自然语言处理
Chap01. 认识AI
本文介绍AI核心概念与大模型开发原理,涵盖人工智能发展历程及Transformer神经网络的关键作用。通过注意力机制,Transformer实现对文本、图像、音频的高效处理,成为GPT等大模型的基础。大语言模型(LLM)利用其持续生成能力,逐字预测输出,实现连贯对话。
|
17小时前
|
缓存 JSON JavaScript
Webpack性能优化
通过按需加载、Tree Shaking、Scope Hoisting 减小打包体积;利用 HappyPack、DllPlugin、优化 Loader 提升打包速度;结合代码压缩与长缓存优化,显著提升 Webpack 构建性能。Webpack4 后 mode 设为 production 可自动启用多数优化。
|
17小时前
|
域名解析 缓存 网络协议
网络优化方案
通过合并压缩资源、合理缓存、DNS预解析、CDN加速、预加载与预渲染、图片优化等手段,减少HTTP请求、提升加载速度。利用hash值更新缓存,结合雪碧图、WebP格式及骨架屏,显著改善页面性能与用户体验,有效降低首屏加载时间。
|
17小时前
|
JavaScript
虚拟滚动技术
插入几万个DOM时,为避免页面卡顿,可采用虚拟滚动技术,仅渲染可视区域内的元素,滚动时动态更新内容,大幅减少DOM数量。相比requestAnimationFrame分批插入,虚拟滚动性能更优,推荐使用react-virtualized等库实现,有效提升渲染效率。(238字)
|
17小时前
|
缓存 监控 JavaScript
前端性能监控指标
前端性能指标包括白屏时间、首屏时间、DOM可操作时间和页面总加载时间。可通过注入代码或`window.performance` API进行量化统计,后者基于浏览器标准接口,提供精确的网络、解析与渲染各阶段耗时数据,助力性能优化。
|
18小时前
|
安全
CSRF攻击
CSRF(跨站请求伪造)攻击利用用户已登录身份,诱导其触发恶意请求,窃取资金或冒用权限。防御措施包括:使用Token验证、SameSite Cookie、检查Referer、禁止第三方携带Cookie,并在关键操作中添加验证码,有效防止非法请求。
|
17小时前
|
缓存 JavaScript 前端开发
重绘回流过程
浏览器渲染流程:解析HTML生成DOM树,CSS生成CSSOM,合并为渲染树,再布局、绘制。DOM树包含所有元素,渲染树仅含可见节点。CSS阻塞渲染但不阻塞DOM解析。重绘因样式变化,回流因布局变化,回流必触发重绘。减少回流重绘可提升性能。
|
17小时前
|
JavaScript 前端开发 测试技术
Angular框架
本文深入解析Angular核心概念,涵盖ng-show与ng-if的性能差异、$rootScope与$scope的关系、表达式机制、Digest周期、定时器与监听器的取消方法。同时探讨Directive的restrict属性、作用域绑定方式及模块间通信策略。此外,介绍性能优化技巧、单元测试实践、Angular 2生命周期钩子、路由机制、事件发射器、AOT编译、安全防护与Shadow DOM等高级主题,全面提升开发技能。
|
17小时前
|
缓存
浏览器缓存
HTTP缓存通过Cache-Control和ETag实现。Cache-Control控制缓存行为,如public/private、no-cache/no-store,以及max-age等时效与验证机制;ETag则用于对比资源是否变更,配合If-None-Match实现304协商缓存。结合内容哈希文件名可优化静态资源更新策略,确保用户获取最新版本。
|
17小时前
|
域名解析 缓存 边缘计算
CDN加速
CDN(内容分发网络)通过在全球部署节点服务器,将源站内容缓存至边缘节点,用户访问时由最近节点提供服务。基于DNS重定向与智能调度,实现就近加速,降低延迟,提升访问速度与网站可用性,有效应对高并发、带宽不足等问题。