• C/C++数据结构之深入了解树与二叉树:概念、存储结构和遍历


    树是一种常见的数据结构,它在计算机科学和数学中都有广泛的应用。树结构的最简单形式是二叉树,本文将深入探讨树和二叉树的概念、存储结构以及二叉树的遍历,并提供一些实际的代码示例来帮助理解这些概念。

    树与二叉树的概念

    树 (Tree)

    树是一种层次性数据结构,由节点(或称为顶点)和边组成。树的一个特点是它没有环路,即不存在从一个节点出发经过若干边后再回到原节点的路径。树通常包括一个根节点,它没有父节点,以及若干子树,每个子树也是一个树。树中的节点分为内部节点和叶节点,内部节点具有子节点,而叶节点没有子节点。

    二叉树 (Binary Tree)

    二叉树是一种特殊的树结构,每个节点最多有两个子节点,通常称为左子节点和右子节点。二叉树有多种变体,包括二叉搜索树(Binary Search Tree)和平衡二叉树(Balanced Binary Tree),它们在数据存储和检索方面具有重要的应用。

    树与二叉树的存储结构

    树和二叉树可以以多种方式进行存储,最常见的方法是使用节点和引用链接的方式。以下是一个简单的二叉树节点的定义:

    1. struct BinaryTreeNode {
    2. int data;
    3. BinaryTreeNode* left;
    4. BinaryTreeNode* right;
    5. BinaryTreeNode(int value) : data(value), left(nullptr), right(nullptr) {}
    6. };

    每个节点包含一个数据元素和指向左子节点和右子节点的指针。通过这种方式,可以递归地构建整个二叉树结构

    二叉树的遍历

    树的遍历是指按照一定规则访问树中的所有节点,以便查找、处理或打印它们的值。常用的二叉树遍历方法包括前序遍历、中序遍历和后序遍历。

    1. 前序遍历 (Preorder Traversal)

    前序遍历从根节点开始,按照根-左-右的顺序遍历节点。以下是递归和非递归的C++代码示例:

    递归方式:
    1. void preorderTraversal(BinaryTreeNode* node) {
    2. if (node != nullptr) {
    3. cout << node->data << " "; // 先访问根节点
    4. preorderTraversal(node->left); // 再访问左子树
    5. preorderTraversal(node->right); // 最后访问右子树
    6. }
    7. }
    非递归方式(使用栈):
    1. #include
    2. void iterativePreorderTraversal(BinaryTreeNode* root) {
    3. if (root == nullptr) return;
    4. stack nodeStack;
    5. nodeStack.push(root);
    6. while (!nodeStack.empty()) {
    7. BinaryTreeNode* current = nodeStack.top();
    8. nodeStack.pop();
    9. cout << current->data << " "; // 访问当前节点
    10. if (current->right != nullptr) {
    11. nodeStack.push(current->right); // 先将右子节点入栈
    12. }
    13. if (current->left != nullptr) {
    14. nodeStack.push(current->left); // 再将左子节点入栈
    15. }
    16. }
    17. }

    2. 中序遍历 (Inorder Traversal)

    中序遍历按照左-根-右的顺序遍历节点。以下是递归和非递归的C++代码示例:

    递归方式:
    1. void inorderTraversal(BinaryTreeNode* node) {
    2. if (node != nullptr) {
    3. inorderTraversal(node->left); // 先访问左子树
    4. cout << node->data << " "; // 再访问根节点
    5. inorderTraversal(node->right); // 最后访问右子树
    6. }
    7. }
    非递归方式(使用栈):
    1. void iterativeInorderTraversal(BinaryTreeNode* root) {
    2. stack nodeStack;
    3. BinaryTreeNode* current = root;
    4. while (current != nullptr || !nodeStack.empty()) {
    5. while (current != nullptr) {
    6. nodeStack.push(current);
    7. current = current->left;
    8. }
    9. current = nodeStack.top();
    10. nodeStack.pop();
    11. cout << current->data << " "; // 访问当前节点
    12. current = current->right;
    13. }
    14. }

    3. 后序遍历 (Postorder Traversal)

    后序遍历按照左-右-根的顺序遍历节点。以下是递归和非递归的C++代码示例:

    递归方式:
    1. void postorderTraversal(BinaryTreeNode* node) {
    2. if (node != nullptr) {
    3. postorderTraversal(node->left); // 先访问左子树
    4. postorderTraversal(node->right); // 再访问右子树
    5. cout << node->data << " "; // 最后访问根节点
    6. }
    7. }
    非递归方式(使用两个栈):
    1. void iterativePostorderTraversal(BinaryTreeNode* root) {
    2. if (root == nullptr) return;
    3. stack s1, s2;
    4. s1.push(root);
    5. while (!s1.empty()) {
    6. BinaryTreeNode* current = s1.top();
    7. s1.pop();
    8. s2.push(current);
    9. if (current->left != nullptr) {
    10. s1.push(current->left);
    11. }
    12. if (current->right != nullptr) {
    13. s1.push(current->right);
    14. }
    15. }
    16. while (!s2.empty()) {
    17. BinaryTreeNode* current = s2.top();
    18. s2.pop();
    19. cout << current->data << " "; // 访问当前节点
    20. }
    21. }

    示例与分析

    考虑以下二叉树:手画不好看,用空格敲出来的。

    1. 1
    2. / \
    3. 2 3
    4. / \
    5. 4 5

    对该二叉树进行前序、中序和后序遍历的C++代码示例如下:

    1. int main() {
    2. BinaryTreeNode* root = new BinaryTreeNode(1);
    3. root->left = new BinaryTreeNode(2);
    4. root->right = new BinaryTreeNode(3);
    5. root->left->left = new BinaryTreeNode(4);
    6. root->left->right = new BinaryTreeNode(5);
    7. cout << "前序遍历:";
    8. preorderTraversal(root);
    9. cout << endl;
    10. cout << "中序遍历:";
    11. inorderTraversal(root);
    12. cout << endl;
    13. cout << "后序遍历:";
    14. postorderTraversal(root);
    15. cout << endl;
    16. return 0;
    17. }

    这些遍历方法将输出以下结果:

    前序遍历: 1 2 4 5 3

    中序遍历: 4 2 5 1 3

    后序遍历: 4 5 2 3 1

    换句话说,三种二叉树遍历方式是根节点在不同位置的遍历方式,它们在处理二叉树时具有不同的应用场景和用途。让我们更详细地讨论一下这三种遍历方式:

    1. 前序遍历 (Preorder Traversal):前序遍历从根节点开始,然后按照根-左-右的顺序遍历节点。在前序遍历中,首先访问根节点,然后递归地访问左子树,最后递归地访右子树。这种遍历方式通常用于创建树的副本或表达式求值。

    2. 中序遍历 (Inorder Traversal):中序遍历按照左-根-右的顺序遍历节点。在中序遍历中,首先递归地访问左子树,然后访问根节点,最后递归地访问右子树。这种遍历方式通常用于获取二叉搜索树的元素按升序排列。

    3. 后序遍历 (Postorder Traversal):后序遍历按照左-右-根的顺序遍历节点。在后序遍历中,首先递归地访问左子树,然后递归地访问右子树,最后访问根节点。这种遍历方式通常用于释放树的内存或执行某些计算。

    这些C++代码示例清晰展示了如何创建一个二叉树,以及如何使用递归和非递归方式执行前序、中序和后序遍历。这些遍历方法在不同的应用中具有不同的用途,例如前序遍历可以用于复制整个树结构,中序遍历用于获取有序数据,后序遍历常用于计算表达式树。

  • 相关阅读:
    Redis Key操作
    [附源码]java毕业设计学院竞赛管理信息系统
    团建游戏------猜猜这是谁
    股票程序化交易如何把交易分析简单化?
    DEC 深度编码聚类函数
    支持中文繁体,支持同时配置并启用飞书和Lark认证,JumpServer堡垒机v3.10.8 LTS版本发布
    HTML 13 HTML a 标签
    C# Winform+Halcon结合标准视觉工具
    Android定时相关
    100114. 元素和最小的山形三元组 II
  • 原文地址:https://blog.csdn.net/qq_72290695/article/details/134095499