news 2026/7/22 16:06:07

DFS序详解:原理、应用与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DFS序详解:原理、应用与实现

1. 什么是DFS序

DFS序(Depth-First Search Order)是指对一棵树进行深度优先遍历时,按照访问顺序给每个节点分配的编号序列。它是树结构的一种线性化表示方法,在算法竞赛和数据结构中有着广泛的应用。

2. DFS序的生成方式

DFS序通常有两种常见的生成方式:

  • 进入时间戳:记录每个节点第一次被访问的时间
  • 欧拉序:记录DFS过程中每个节点的进入和离开时间

3. DFS序的基本性质

DFS序具有以下重要性质:

  1. 子树连续性:任意节点的子树在DFS序中对应一段连续区间
  2. 祖先关系:如果节点u是节点v的祖先,那么u的DFS序一定在v之前
  3. 区间包含:子树对应的区间完全包含其所有后代节点对应的区间

4. DFS序的代码实现

以下是使用C++实现DFS序的示例代码:

#include <iostream> #include <vector> using namespace std; const int MAXN = 100005; vector<int> graph[MAXN]; int tin[MAXN], tout[MAXN]; // 进入和离开时间 int timer = 0; void dfs(int u, int parent) { tin[u] = ++timer; // 记录进入时间 for (int v : graph[u]) { if (v != parent) { dfs(v, u); } } tout[u] = timer; // 记录离开时间 } int main() { int n; // 节点数 cin >> n; // 构建树(无向图) for (int i = 1; i < n; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } // 从根节点1开始DFS dfs(1, 0); // 输出每个节点的DFS序区间 for (int i = 1; i <= n; i++) { cout << "节点" << i << ": [" << tin[i] << ", " << tout[i] << "]" << endl; } return 0; }

5. DFS序的应用场景

5.1 子树查询与更新

利用子树在DFS序中的连续性,可以将树上的子树操作转化为区间操作:

  • 子树求和:查询子树所有节点的权值和
  • 子树更新:给子树所有节点增加某个值
  • 子树最值:查询子树中的最大值或最小值

5.2 LCA(最近公共祖先)

DFS序结合RMQ(区间最小值查询)可以高效求解LCA问题。

5.3 树链剖分

DFS序是树链剖分的基础,用于将树分解为多条链,便于进行路径查询和更新。

5.4 离线查询处理

结合莫队算法,可以处理树上的离线查询问题。

6. DFS序的变体

6.1 欧拉序

记录DFS过程中每个节点的进入和离开,形成长度为2n-1的序列。

6.2 DFS序+时间戳

同时记录进入时间tin[u]和离开时间tout[u],满足:

  • 节点v在节点u的子树中 ⇔ tin[u] ≤ tin[v] ≤ tout[u]

6.3 重链剖分DFS序

优先遍历重儿子,使得每条重链在DFS序中连续,优化路径操作。

7. 实战例题分析

例题1:子树求和

给定一棵树,每个节点有一个权值,支持两种操作:

  1. 查询某个子树所有节点的权值和
  2. 修改某个节点的权值

解决方案:使用DFS序将树转化为数组,用树状数组或线段树维护。

例题2:路径查询

查询树上两个节点路径上的权值和。

解决方案:结合DFS序和树链剖分,将路径分解为若干条链的区间查询。

8. 时间复杂度分析

操作时间复杂度空间复杂度
生成DFS序O(n)O(n)
子树查询O(log n)O(n)
子树更新O(log n)O(n)
路径查询O(log² n)O(n log n)

9. 常见问题与注意事项

  • 根节点的选择:DFS序的结果与根节点选择有关,但性质保持不变
  • 有根树与无根树:DFS序通常用于有根树,需要先指定根节点
  • 内存优化:对于大规模数据,可以使用时间戳代替完整的DFS序数组
  • 边界处理:注意tin和tout数组的初始化,避免越界访问

10. 总结

DFS序是树结构线性化的重要工具,它将树上的操作转化为序列上的操作,大大简化了问题的复杂度。掌握DFS序及其应用,对于解决树相关算法问题具有重要意义。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/22 16:05:24

汉化paraview下载安装包

官网地址&#xff1a;https://www.paraview.org/download/。官网下载有可能较慢。这里提供了linux安装包、Windows的绿色包和安装包。并提供了汉化包&#xff0c;汉化包应该是5.12之后版本可以进行汉化&#xff0c;之前版本似乎不太行。 链接: https://pan.baidu.com/s/1xz5Ev5…

作者头像 李华
网站建设 2026/7/22 16:03:13

Claude Chrome扩展高危漏洞实战检测与防御方案(CVSS9.6权限劫持)

前置导读 2026年7月&#xff0c;安全厂商Manifold Security与IANS Research公开披露了一则影响范围极广的高危漏洞。Anthropic旗下Claude for Chrome浏览器扩展&#xff0c;存在两处可组合利用的逻辑漏洞&#xff0c;恶意攻击者只需借助普通恶意Chrome扩展&#xff0c;就能静默…

作者头像 李华
网站建设 2026/7/22 16:02:59

嵌入式DMA开发实战:EDMA3中断、队列与优先级机制深度解析

1. 项目概述与核心价值 在嵌入式系统&#xff0c;尤其是高性能处理器&#xff08;如TI的C6000系列DSP&#xff09;的开发中&#xff0c;数据搬移的效率直接决定了整个系统的性能天花板。当你在处理音频流、视频帧或者雷达回波数据时&#xff0c;如果让CPU亲自去搬运每一个字节&…

作者头像 李华
网站建设 2026/7/22 15:56:32

嵌入式UART/USB寄存器配置详解:从低功耗唤醒到DMA优化

1. 项目概述&#xff1a;深入嵌入式通信的寄存器世界 在嵌入式开发领域&#xff0c;无论是调试信息输出、传感器数据采集&#xff0c;还是与上位机进行复杂的数据交换&#xff0c;串行通信都是不可或缺的一环。UART和USB&#xff0c;作为两种最经典、应用最广泛的串行通信接口&…

作者头像 李华
网站建设 2026/7/22 15:56:17

2026科技创新的国内EMBA中立择校测评

民营企业家、企业创始人选读EMBA&#xff0c;大多纠结三大问题&#xff1a;课程是否贴合科创转型、圈层是否匹配企业发展、资源能否助力出海与数字化升级。本文从全球办学排名、院校办学定位、课程体系、学员圈层、产业资源五大维度&#xff0c;对科技创新的国内EMBA主流项目做…

作者头像 李华