当前位置: 首页 > news >正文

【数据结构】二叉树-图解深度优先搜索(递归法、迭代法)

二叉树的遍历方式

二叉树的遍历策略可以分为两种:深度优先(DFS)与 广度优先(BFS)递归法迭代法则作为这类策略的实现方式。它们之间的关系可以形容为:遍历策略是“目标”,而实现方式是“手段”,且一种遍历策略可以用不同的实现方式来完成

这里就先来讲解一下深度优先遍历。

深度优先遍历

深度优先搜索既可以使用递归法实现(基于 结构实现),也可以使用迭代法实现(同样也基于 结构实现)。前序遍历、中序遍历、后序遍历都属于深度优先遍历。

前序遍历(中 左 右)

二叉树的前序遍历,就是先输出根节点,再遍历左子树,最后遍历右子树(也就是中左右),遍历左子树和右子树的时候,同样遵循前序遍历的规则。
在这里插入图片描述
递归法思路如下:

public void preOrder(TreeNode root){if(root == null){return;}system.out.println(root.data);preOrder(root.left);preOrder(root.right);
}

迭代法思路如下:

  1. 根节点入栈
  2. 循环(栈不为空):
    • 栈顶元素出栈并访问
    • 右子节点入栈(如果存在)
    • 左子节点入栈(如果存在)

为什么总是先右后左?因为栈是后进先出的,先压入右节点,再压入左节点,在出栈时就会先弹出左节点,再弹出右节点,这样就保证了"根→左→右"的访问顺序。

流程图及代码如下:
在这里插入图片描述

public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>(); // 数组存储遍历结果if (root == null) return result;Deque<TreeNode> stack = new ArrayDeque<>(); // 双端队列作为栈stack.push(root); // 根节点入栈while (!stack.isEmpty()) {TreeNode node = stack.pop(); // 弹出栈顶元素result.add(node.val); // 访问当前节点// 先右后左,保证出栈时先左后右if (node.right != null) {stack.push(node.right);}if (node.left != null) {stack.push(node.left);}}return result;
}

中序遍历(左 中 右)

在这里插入图片描述
二叉树的中序遍历,就是先递归中序遍历左子树,再输出根结点的值,再递归中序遍历右子树(也就是左中右),大家可以想象成一巴掌把树压扁,父结点被拍到了左子节点和右子节点的中间,如下图所示:
在这里插入图片描述
递归法思路如下:

public void inOrder(TreeNode root){if(root == null){return;}inOrder(root.left);system.out.println(root.data);inOrder(root.right);
}

迭代法思路如下:
中序遍历的逻辑比较特别,因为在这里我们访问节点的顺序与处理的顺序不一样了,所以需要另外借助一个指针来帮助我们遍历二叉树。

  1. 进入循环,从根节点开始,将所有左子节点入栈
  2. 循环内(栈不为空 或 当前节点不为空):
    • 将当前节点的所有左子节点入栈
    • 弹出栈顶节点并访问
    • 转向右子节点

流程图及代码如下:
在这里插入图片描述

public List<Integer> inorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();Deque<TreeNode> stack = new ArrayDeque<>();TreeNode current = root; // 当前节点指针while (!stack.isEmpty() || current != null) {// 将当前节点的所有左子节点入栈while (current != null) {stack.push(current);current = current.left;}// 弹出栈顶节点(最左节点)current = stack.pop();result.add(current.val); // 访问该节点// 转向右子树current = current.right;}return result;
}

后序遍历(左 右 中)

二叉树的后序遍历,就是先递归后序遍历左子树,再递归后序遍历右子树(也就是左右中),最后输出根节点的值。
在这里插入图片描述
递归法思路如下:

public void postOrder(TreeNode root){if(root == null){return;}postOrder(root.left);postOrder(root.right);system.out.println(root.data);
}

迭代法思路如下:

  1. 根节点入栈
  2. 循环(栈不为空):
    • 栈顶元素出栈并访问
    • 左子节点入栈(如果存在)
    • 右子节点入栈(如果存在)
  3. 翻转集合/数组

后续遍历的实现思路与前序遍历非常相似,简单来说我们就是需要将"中左右"的顺序转换为"左右中",可以分为以下两步来实现:1.将节点的入栈顺序改为先左后右,即"中右左";2.再反转集合/数组,即"左右中"。

流程图及代码如下:
在这里插入图片描述

public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>(); // 数组存储遍历结果if (root == null) return result;Deque<TreeNode> stack = new ArrayDeque<>(); // 双端队列作为栈stack.push(root); // 根节点入栈while (!stack.isEmpty()) {TreeNode node = stack.pop(); // 弹出栈顶元素result.add(node.val); // 访问当前节点// 先右后左,保证出栈时先左后右if (node.right != null) {stack.push(node.right);}if (node.left != null) {stack.push(node.left);}}// 反转结果:从左 -> 右 -> 根 变成 左 -> 右 -> 根Collections.reverse(result);return result;
}
http://www.dtcms.com/a/418725.html

相关文章:

  • 邯郸企业网站建设报价接收新网站如何做诊断
  • 做体力活的网站上海网站制作公司哪
  • Jenkins运维之路(Jenkins使用Mysql作为信息存储)
  • 爬虫访问第三方 HTTPS 网站时遇到的 SSL 异常处理
  • JavaWeb 课堂笔记 —— 22 登录校验
  • 整合营销传播案例广西网络优化seo
  • Mac电脑解决 npm 和 Yarn 安装时的证书过期问题
  • JavaScript继承详讲
  • 怎么理解ES的shard和segment
  • AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
  • 新乡网站关键词优化电商网站开发实战视频教程
  • 公司无网站无平台怎么做外贸wordpress检查php版本号
  • Spark核心Shuffle详解(二)ShuffleHandler
  • React Native启动性能优化实战:Hermes + RAM Bundles + 懒加载
  • 怎么做淘宝客个人网站wordpress可视化编辑插件下载
  • [C++项目框架]gflags和gtest的简单介绍
  • Vue2 和 Vue3 中使用 Vue Router 的详细过程
  • 微服务项目->在线oj系统(Java-Spring)-后台管理(2)
  • 【MySQL体系】第2篇:MySQL索引类型和原理
  • flash型的著名网站网站开发公司怎么接单
  • 【第五章:计算机视觉-项目实战之图像分割实战】2.图像分割实战:人像抠图-(1)人像抠图Image Matting算法详解
  • 使用 PyTorch 构建并训练 CNN 模型
  • 如何做电影网站狼视听seo外包优化服务商
  • blender布局工作区突然变得很卡
  • 【计算机视觉】图像去雾技术
  • 工信部网站icp备案号文艺范wordpress主题
  • 树莓派无法播放哔哩哔哩等视频
  • 华为芯片泄密案警示:用Curtain e-locker阻断内部数据泄露
  • 记一次达梦数据库的查询异常
  • 泸州市建设工程管理局网站58网站怎么做品牌推广