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

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

树与二叉树的概念

树 (Tree)

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

二叉树 (Binary Tree)

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

树与二叉树的存储结构

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

struct BinaryTreeNode {int data;BinaryTreeNode* left;BinaryTreeNode* right;BinaryTreeNode(int value) : data(value), left(nullptr), right(nullptr) {}
};

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

二叉树的遍历

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

1. 前序遍历 (Preorder Traversal)

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

递归方式:
void preorderTraversal(BinaryTreeNode* node) {if (node != nullptr) {cout << node->data << " ";  // 先访问根节点preorderTraversal(node->left);  // 再访问左子树preorderTraversal(node->right);  // 最后访问右子树}
}
非递归方式(使用栈):
#include <stack>void iterativePreorderTraversal(BinaryTreeNode* root) {if (root == nullptr) return;stack<BinaryTreeNode*> nodeStack;nodeStack.push(root);while (!nodeStack.empty()) {BinaryTreeNode* current = nodeStack.top();nodeStack.pop();cout << current->data << " ";  // 访问当前节点if (current->right != nullptr) {nodeStack.push(current->right);  // 先将右子节点入栈}if (current->left != nullptr) {nodeStack.push(current->left);  // 再将左子节点入栈}}
}

2. 中序遍历 (Inorder Traversal)

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

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

3. 后序遍历 (Postorder Traversal)

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

递归方式:
void postorderTraversal(BinaryTreeNode* node) {if (node != nullptr) {postorderTraversal(node->left);  // 先访问左子树postorderTraversal(node->right);  // 再访问右子树cout << node->data << " ";  // 最后访问根节点}
}
非递归方式(使用两个栈):
void iterativePostorderTraversal(BinaryTreeNode* root) {if (root == nullptr) return;stack<BinaryTreeNode*> s1, s2;s1.push(root);while (!s1.empty()) {BinaryTreeNode* current = s1.top();s1.pop();s2.push(current);if (current->left != nullptr) {s1.push(current->left);}if (current->right != nullptr) {s1.push(current->right);}}while (!s2.empty()) {BinaryTreeNode* current = s2.top();s2.pop();cout << current->data << " ";  // 访问当前节点}
}

示例与分析

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

        1/ \2   3/ \4   5

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

int main() {BinaryTreeNode* root = new BinaryTreeNode(1);root->left = new BinaryTreeNode(2);root->right = new BinaryTreeNode(3);root->left->left = new BinaryTreeNode(4);root->left->right = new BinaryTreeNode(5);cout << "前序遍历:";preorderTraversal(root);cout << endl;cout << "中序遍历:";inorderTraversal(root);cout << endl;cout << "后序遍历:";postorderTraversal(root);cout << endl;return 0;
}

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/151792.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

雷电_安卓模拟器安装burpsuit_CA证书

雷电_安卓模拟器安装burpsuit_CA证书 文章目录 雷电_安卓模拟器安装burpsuit_CA证书雷电模拟器官网&#xff1a;https://www.ldmnq.com 安装burpsuit证书1 打开雷电模拟器右上角的winfi图标 -->点击齿轮2 修改网络3 选择高级 —》手动4 查看真实机IP的地址&#xff0c;选择虚…

为什么多线程会带来性能问题?

为什么多线程会带来性能问题&#xff1f; 什么是性能问题 在上一篇中&#xff0c;我们已经学习了多线程带来的线程安全问题&#xff0c;但对于多线程而言&#xff0c;它不仅可能会带来线程安全问题&#xff0c;还有可能会带来性能问题&#xff0c;也许你会奇怪&#xff0c;我…

刚刚:腾讯云3年轻量2核2G4M服务器优惠价格366元三年

腾讯云3年轻量2核2G4M服务器&#xff0c;2023双十一优惠价格366元三年&#xff0c;自带4M公网带宽&#xff0c;下载速度可达512KB/秒&#xff0c;300GB月流量&#xff0c;50GB SSD盘系统盘&#xff0c;腾讯云百科txybk.com分享腾讯云轻量2核2G4M服务器性能、优惠活动、购买条件…

mac vscode 使用 clangd

C 的智能提示 IntelliSense 非常不准&#xff0c;我们可以使用 clangd clangd 缺点就是配置繁琐&#xff0c;优点就是跳转和提示代码精准 开启 clangd 之后会提示你关闭 IntelliSense 1、安装插件 clangd 搜索第一个下载多的就是 2、配置 clangd 可执行程序路径 clangd 插…

react实现步进器

创建一个步进器组件&#xff0c;包含当前步骤&#xff08;currentStep&#xff09;的状态以及前进和后退的操作&#xff1a; import React, { useState } from react;function Stepper() {const [currentStep, setCurrentStep] useState(1);const handleNext () > {setCu…

环形链表(C++解法)

题目 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#…

如何能够在发现问题和提问的时候一并带出自己的解决方案

1. 充分理解问题&#xff1a; 在提出问题之前&#xff0c;确保你已经完全理解了问题的本质。从不同的角度分析问题&#xff0c;确保没有遗漏任何重要的信息或者上下文。 2. 进行自我调查和研究&#xff1a; 在向他人寻求帮助之前&#xff0c;尝试自己解决问题。利用网络资源…

【proteus】8086 写一个汇编程序并调试

参考书籍&#xff1a;微机原理与接口技术——基于8086和Proteus仿真&#xff08;第3版&#xff09;p103-105&#xff0c;p119-122. 参考程序是p70&#xff0c;例4-1 在上一篇的基础上&#xff1a; 创建项目和汇编文件 写一个汇编程序并编译 双击8086的元件图&#xff1a; …

数据结构和算法——用C语言实现所有排序算法

文章目录 前言排序算法的基本概念内部排序插入排序直接插入排序折半插入排序希尔排序 交换排序冒泡排序快速排序 选择排序简单选择排序堆排序 归并排序基数排序 外部排序多路归并败者树置换——选择排序最佳归并树 前言 本文所有代码均在仓库中&#xff0c;这是一个完整的由纯…

【计算机网络笔记】DNS报文格式

DNS 提供域名到主机IP地址的映射  域名服务的三大要素&#xff1a;  域&#xff08;Domain&#xff09;和域名(Domain name)&#xff1a; 域指由地 理位置或业务类型而联系在一起的一组计算机构 成。  主机&#xff1a;由域名来标识。域名是由字符和&#xff08;或&a…

mac安装jenkins

1、安装jenkins之前确认是否安装了homebrew 2、开始安装jenkins 安装完如下图则安装完成 3、不想用默认ip和端口的自己改一下ip和端口 4、启动jenkins brew services restart jenkins 使用自己修改后的ip:port http://0.0.0.0:8088 根据提示信息&#xff0c;拿到管理员密码&…

java - IDEA IDE - 设置字符串断点

文章目录 java - IDEA IDE - 设置字符串断点概述笔记END java - IDEA IDE - 设置字符串断点 概述 IDE环境为IDEA2022.3 在看一段序列化的代码, 想找出报错抛异常那个点, 理解一下代码实现. 因为序列化代码实现在第三方jar包中, 改不了(只读的). 根本数不清第几次才会开始报…