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

数据结构:二叉树的广度优先遍历与深度优先遍历(递归方法)。C++及其新特性分别实现

在二叉树的遍历中,广度优先遍历(BFS)和深度优先遍历(DFS)是两种常用的遍历方法。它们的遍历顺序和实现方法有所不同。以下是这两种遍历方法的详细解释和 C++ 实现。

1. 广度优先遍历(BFS)

广度优先遍历使用队列(queue)来实现,它按层次从上到下、从左到右遍历树的每一层。

实现思路:
  1. 从根节点开始,将其加入队列。
  2. 从队列中取出节点,访问该节点,并将其左右子节点按顺序加入队列。
  3. 重复以上步骤,直到队列为空。
C++ 代码实现:
#include <iostream>
#include <queue>struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};void BFS(TreeNode* root) {if (root == nullptr) return;std::queue<TreeNode*> q;q.push(root);while (!q.empty()) {TreeNode* node = q.front();q.pop();std::cout << node->val << " ";if (node->left) q.push(node->left);if (node->right) q.push(node->right);}
}int main() {TreeNode* root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);root->left->right = new TreeNode(5);root->right->left = new TreeNode(6);root->right->right = new TreeNode(7);std::cout << "BFS traversal: ";BFS(root);std::cout << std::endl;return 0;
}

2. 深度优先遍历(DFS)

深度优先遍历有三种主要方法:前序遍历、中序遍历和后序遍历。它们都可以通过递归或使用栈(stack)来实现。

2.1 前序遍历(Preorder Traversal)

前序遍历顺序是:根节点 -> 左子树 -> 右子树。

C++ 代码实现(递归):
void Preorder(TreeNode* root) {if (root == nullptr) return;std::cout << root->val << " ";Preorder(root->left);Preorder(root->right);
}
2.2 中序遍历(Inorder Traversal)

中序遍历顺序是:左子树 -> 根节点 -> 右子树。

C++ 代码实现(递归):
void Inorder(TreeNode* root) {if (root == nullptr) return;Inorder(root->left);std::cout << root->val << " ";Inorder(root->right);
}

2.4 深度优先遍历(DFS)整体实现

C++ 代码实现:
int main() {TreeNode* root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);root->left->right = new TreeNode(5);root->right->left = new TreeNode(6);root->right->right = new TreeNode(7);std::cout << "Preorder traversal: ";Preorder(root);std::cout << std::endl;std::cout << "Inorder traversal: ";Inorder(root);std::cout << std::endl;std::cout << "Postorder traversal: ";Postorder(root);std::cout << std::endl;return 0;
}
输出:
Preorder traversal: 1 2 4 5 3 6 7
Inorder traversal: 4 2 5 1 6 3 7
Postorder traversal: 4 5 2 6 7 3 1

总结

  • 广度优先遍历(BFS):使用队列,按层次从上到下、从左到右遍历。
  • 深度优先遍历(DFS)
    • 前序遍历(根 -> 左 -> 右)
    • 中序遍历(左 -> 根 -> 右)
    • 后序遍历(左 -> 右 -> 根)

 新特性实现

下面是一个使用 C++11 修改后的代码。C++11 引入了一些新特性,如智能指针(std::unique_ptrstd::shared_ptr)和基于范围的 for 循环等,这些特性可以使代码更加现代化和安全。这里,我将使用 std::unique_ptr 来管理二叉树节点的内存,避免手动的内存管理。

#include <iostream>
#include <queue>
#include <memory>  // For std::unique_ptr// 使用 std::unique_ptr 来管理内存
struct TreeNode {std::unique_ptr<TreeNode> left;int val;std::unique_ptr<TreeNode> right;TreeNode(int val) : val(val), left(nullptr), right(nullptr) {}
};// 广度优先遍历(BFS)
void BFS(TreeNode* root) {if (root == nullptr) return;std::queue<TreeNode*> q;q.push(root);while (!q.empty()) {TreeNode* node = q.front();q.pop();std::cout << node->val << " ";if (node->left) q.push(node->left.get());if (node->right) q.push(node->right.get());}
}// 深度优先遍历(DFS)// 1、前序遍历(根节点 -> 左子树 -> 右子树)
void Preorder(TreeNode* root) {if (root == nullptr) return;std::cout << root->val << " ";Preorder(root->left.get());Preorder(root->right.get());
}// 2、中序遍历(左子树 -> 根节点 -> 右子树)
void Inorder(TreeNode* root) {if (root == nullptr) return;Inorder(root->left.get());std::cout << root->val << " ";Inorder(root->right.get());
}// 3、后序遍历(左子树 -> 右子树 -> 根节点)
void Postorder(TreeNode* root) {if (root == nullptr) return;Postorder(root->left.get());Postorder(root->right.get());std::cout << root->val << " ";
}int main() {auto root = std::make_unique<TreeNode>(1);root->left = std::make_unique<TreeNode>(2);root->right = std::make_unique<TreeNode>(3);root->left->left = std::make_unique<TreeNode>(4);root->left->right = std::make_unique<TreeNode>(5);root->right->left = std::make_unique<TreeNode>(6);root->right->right = std::make_unique<TreeNode>(7);/*std::cout << "BFS traversal: ";BFS(root.get());std::cout << std::endl;*/std::cout << "Preorder traversal: ";Preorder(root.get());std::cout << std::endl;std::cout << "Inorder traversal: ";Inorder(root.get());std::cout << std::endl;std::cout << "Postorder traversal: ";Postorder(root.get());std::cout << std::endl;return 0;
}

代码说明:
  1. 使用 std::unique_ptr

    • TreeNode 的左右子节点使用 std::unique_ptr 进行管理,确保内存自动释放,避免手动调用 delete
  2. std::make_unique

    • C++14 引入的 std::make_unique 函数用于创建 std::unique_ptr 对象,它使代码更加简洁和安全。
  3. get() 方法

    • 在遍历树时,通过 get() 方法获取原始指针,因为 std::queue 中存储的是裸指针(TreeNode*),而不是智能指针。
  4. 内存安全

    • 由于使用了 std::unique_ptr,在树不再需要时(例如当程序退出时),所有节点的内存都会自动释放,无需手动管理。

另外:全局函数 Preorder、Inorder、Postorder的形参可以改写为

const std::unique_ptr<TreeNode>& root  让代码更简洁一些

输出结果:

代码的输出与之前的实现相同,依然是:

Preorder traversal: 1 2 4 5 3 6 7 
Inorder traversal: 4 2 5 1 6 3 7 
Postorder traversal: 4 5 2 6 7 3 1 

这种修改使得代码在 C++11 风格下更加现代化且易于维护,同时也充分利用了智能指针的优势

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Apache Tomcat 信息泄露漏洞CVE-2024-21733、CVE-2024-24549和CVE-2024-34750排查处理
  • Matlab2021b通过CNN、CNN-LSTM模型实现对声音信号的二分类与四分类
  • HTML静态网页成品作业(HTML+CSS)——安徽宣笔设计制作(5个页面)
  • 使用 ESP32 和 TFT 屏幕显示实时天气信息 —— 基于 OpenWeatherMap API
  • 微服务架构设计中的常见的10种设计模式
  • vuex的原理和使用方法
  • UniFab 是一款由人工智慧驅動的視訊增強器+ crack
  • string字符串和json对象相互转换问题
  • 认知杂谈16
  • CompletableFuture 的使用和实际业务中的应用
  • 大话回合手游【精品西游之鸿鹄西游精修商业开服端】最新整理WIN系特色服务端+安卓苹果双端+GM后台
  • 一个手机到手机之间通话经过了哪些设备
  • SQL - 基础大汇总
  • CSS知识点详解:display+float
  • AWS CDK测试初探:掌握Assertion测试模式
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • CSS实用技巧
  • js数组之filter
  • Linux中的硬链接与软链接
  • Redis的resp协议
  • Spark学习笔记之相关记录
  • Spring Boot快速入门(一):Hello Spring Boot
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • webpack+react项目初体验——记录我的webpack环境配置
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 欢迎参加第二届中国游戏开发者大会
  • 实现菜单下拉伸展折叠效果demo
  • 使用 QuickBI 搭建酷炫可视化分析
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 协程
  • 《天龙八部3D》Unity技术方案揭秘
  • PostgreSQL 快速给指定表每个字段创建索引 - 1
  • 扩展资源服务器解决oauth2 性能瓶颈
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • # Maven错误Error executing Maven
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (LeetCode C++)盛最多水的容器
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (三)Kafka离线安装 - ZooKeeper开机自启
  • (四)opengl函数加载和错误处理
  • (算法)N皇后问题
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • (自用)网络编程
  • .ai域名是什么后缀?
  • .net core Swagger 过滤部分Api
  • .NET+WPF 桌面快速启动工具 GeekDesk
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?
  • @AliasFor 使用
  • @JsonFormat 和 @DateTimeFormat 的区别
  • @property括号内属性讲解
  • [ActionScript][AS3]小小笔记