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

数据结构之二叉树

数据结构之二叉树

  • 数据结构之二叉树
    • 1. 什么是二叉树?
    • 2. 基本概念
    • 3. 二叉树的基本形态
    • 4. 二叉树的性质
    • 5. 特殊二叉树
    • 6. 二叉树的存储
    • 7. 二叉树的遍历
      • 7.1 前序遍历
      • 7.2 中序遍历
      • 7.3 后序遍历
      • 7.4 层次遍历
    • 8. 应用场景
    • 9. 实例代码
      • 9.1 示例树结构
      • 9.2 输出结果

数据结构之二叉树


1. 什么是二叉树?

二叉树(Binary Tree)是一种特殊的树形数据结构,其中每个节点最多有两个子节点,分别称为左子节点右子节点。二叉树可以为空(没有节点),或者由一个根节点和两棵互不相交的子树(左子树和右子树)组成。

二叉树的特点是:

  • 每个节点最多有两个子节点。
  • 左子树和右子树是有序的,不能互换。

2. 基本概念

  • 节点(Node):二叉树的基本单位,包含数据域和指针域。
  • 根节点(Root):二叉树的顶层节点,没有父节点。
  • 叶子节点(Leaf):没有子节点的节点。
  • 父节点(Parent):有子节点的节点。
  • 子节点(Child):某个节点的直接下级节点。
  • 深度(Depth):从根节点到某个节点的路径长度(根节点的深度为0)。
  • 高度(Height):从某个节点到叶子节点的最长路径长度(叶子节点的高度为0)。
  • 层次(Level):根节点为第0层,其子节点为第1层,以此类推。

3. 二叉树的基本形态

二叉树有以下几种基本形态:

  1. 空树:没有节点的二叉树。
  2. 只有一个根节点:根节点没有子节点。
  3. 只有左子树:根节点只有左子节点,右子节点为空。
  4. 只有右子树:根节点只有右子节点,左子节点为空。
  5. 左右子树都存在:根节点同时有左子节点和右子节点。

4. 二叉树的性质

二叉树具有以下重要性质:

  1. 性质1:在二叉树的第 i 层上,最多有 2^i 个节点 (i >= 0)。
    • 例如:
      • 第 0 层最多有 2^0 = 1 个节点(根节点)。
      • 第 1 层最多有 2^1 = 2 个节点。
  2. 性质2:深度为 k 的二叉树,最多有 2^(k+1) - 1 个节点 (k >= 0)。
    • 例如:
      • 深度为 0 的二叉树,最多有 2^(0+1) - 1 = 1 个节点。
      • 深度为 1 的二叉树,最多有 2^(1+1) - 1 = 3 个节点。
      • 深度为 2 的二树,最多有 2^(2+1) - 1 = 7 个节点。
  3. 性质3:对于任意一棵二叉树,如果叶子节点数为 n0,度为 2 的节点数为 n2,则满足关系式:n0 = n2 + 1
    • 说明:
      • 叶子节点是指没有子节点的节点。
      • 度为 2 的节点是指有两个子节点的节点。
  4. 性质4:具有 n 个节点的完全二叉树,其深度为:log2(n) 向下取整后加 1
    • 说明:
      • 完全二叉树是指除了最后一层外,其他层都是满的,最后一层的节点尽量靠左排列。
  5. 性质5:对于一棵完全二叉树,如果对节点从 0 开始编号,则:
    • 父节点为 i,则:
      • 左子节点编号为 2*i + 1
      • 右子节点编号为 2*i + 2
    • 子节点编号为 i,则:
      • 父节点编号为 (i - 1) // 2 (整数除法)

5. 特殊二叉树

  1. 满二叉树(Full Binary Tree)

    • 每一层的节点数都达到最大值,即第 i 层有 2^i 个节点。
    • 深度为 k 的满二叉树,总节点数为 2^(k+1) - 1。
  2. 完全二叉树(Complete Binary Tree)

    • 除了最后一层,其他层都是满的,且最后一层的节点尽量靠左排列。
    • 适合用数组存储。
  3. 二叉搜索树(Binary Search Tree, BST)

    • 左子树的所有节点值小于根节点值,右子树的所有节点值大于根节点值。
    • 中序遍历结果是有序的。
  4. 平衡二叉树(Balanced Binary Tree)

    • 任意节点的左右子树高度差不超过1。
    • 例如:AVL树、红黑树。

6. 二叉树的存储

  1. 链式存储

    • 使用节点对象和指针表示二叉树。
    • 每个节点包含数据域和两个指针域(左子节点和右子节点)。
    struct TreeNode {
        int value;
        TreeNode* left;
        TreeNode* right;
        TreeNode(int val) : value(val), left(nullptr), right(nullptr) {}
    };
    
  2. 顺序存储

    • 使用数组存储完全二叉树。
    • 对于节点 i,左子节点为 2i + 1,右子节点为 2i + 2,父节点为 (i - 1) // 2(其中//表示整数除法)

7. 二叉树的遍历

  1. 前序遍历(Pre-order):根 -> 左 -> 右
  2. 中序遍历(In-order):左 -> 根 -> 右
  3. 后序遍历(Post-order):左 -> 右 -> 根
  4. 层次遍历(Level-order):按层从上到下、从左到右访问节点。

7.1 前序遍历

void preOrderTraversal(TreeNode* root) {
    if (root == nullptr) return; // 递归终止条件
    cout << root->value << " ";  // 访问根节点
    preOrderTraversal(root->left);  // 遍历左子树
    preOrderTraversal(root->right); // 遍历右子树
}

7.2 中序遍历

void inOrderTraversal(TreeNode* root) {
    if (root == nullptr) return;   // 递归终止条件
    inOrderTraversal(root->left);  // 遍历左子树
    cout << root->value << " ";    // 访问根节点
    inOrderTraversal(root->right); // 遍历右子树
}

7.3 后序遍历

void postOrderTraversal(TreeNode* root) {
    if (root == nullptr) return;     // 递归终止条件
    postOrderTraversal(root->left);  // 遍历左子树
    postOrderTraversal(root->right); // 遍历右子树
    cout << root->value << " ";      // 访问根节点
}

7.4 层次遍历

#include <queue>

void levelOrderTraversal(TreeNode* root) {
    if (root == nullptr) return;

    queue<TreeNode*> q;
    q.push(root); // 根节点入队

    while (!q.empty()) {
        TreeNode* node = q.front(); // 取出队首节点
        q.pop();
        cout << node->value << " "; // 访问当前节点

        if (node->left != nullptr) {
            q.push(node->left); // 左子节点入队
        }
        if (node->right != nullptr) {
            q.push(node->right); // 右子节点入队
        }
    }
}

8. 应用场景

  • 二叉搜索树:用于动态查找、插入和删除操作。
  • 堆(Heap):用于优先队列。
  • 哈夫曼树:用于数据压缩。
  • 表达式树:用于编译器的语法分析。

9. 实例代码

  1. 节点定义:使用 TreeNode 结构表示二叉树的节点,每个节点包含一个值指向左右子节点的指针。
  2. 遍历方法:
    • 前序、中序、后序遍历使用递归实现。
    • 层次遍历使用队列实现,通过逐层访问节点。
  3. 树的构建createSampleTree 函数手动构建了一棵简单的完全二叉树。
#include <iostream>
#include <queue> // 用于层次遍历
using namespace std;

// 定义二叉树的节点结构
struct TreeNode {
    int value;             // 数据域
    TreeNode* left;        // 左子节点指针
    TreeNode* right;       // 右子节点指针

    // 构造函数
    TreeNode(int val) : value(val), left(nullptr), right(nullptr) {}
};

// 前序遍历:根 -> 左 -> 右
void preOrderTraversal(TreeNode* root) {
    if (root == nullptr) return;
    cout << root->value << " ";           // 访问根节点
    preOrderTraversal(root->left);        // 遍历左子树
    preOrderTraversal(root->right);       // 遍历右子树
}

// 中序遍历:左 -> 根 -> 右
void inOrderTraversal(TreeNode* root) {
    if (root == nullptr) return;
    inOrderTraversal(root->left);         // 遍历左子树
    cout << root->value << " ";           // 访问根节点
    inOrderTraversal(root->right);        // 遍历右子树
}

// 后序遍历:左 -> 右 -> 根
void postOrderTraversal(TreeNode* root) {
    if (root == nullptr) return;
    postOrderTraversal(root->left);       // 遍历左子树
    postOrderTraversal(root->right);      // 遍历右子树
    cout << root->value << " ";           // 访问根节点
}

// 层次遍历:从到下,从左到右
void levelOrderTraversal(TreeNode* root) {
    if (root == nullptr) return;

    queue<TreeNode*> q; // 辅助队列
    q.push(root); // 根节点入队

    while (!q.empty()) {
        TreeNode* node = q.front(); // 获取队首节点
        q.pop();                    // 出队
        cout << node->value << " "; // 访问当前节点

        if (node->left != nullptr) {
            q.push(node->left);     // 左子节点入队
        }
        if (node->right != nullptr) {
            q.push(node->right);    // 右子节点入队
        }
    }
}

// 创建一个简单的二叉树
TreeNode* createSampleTree() {
    // 创建节点
    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);

    return root; // 返回根节点
}

int main() {
    // 创建示例二叉树
    TreeNode* root = createSampleTree();

    // 打印各类遍历结果
    cout << "前序遍历 (Pre-order): ";
    preOrderTraversal(root);
    cout << endl;

    cout << "中序遍历In-order): ";
    inOrderTraversal(root);
    cout << endl;

    cout << "后序遍历 (Post-order): ";
    postOrderTraversal(root);
    cout << endl;

    cout << "层次遍历 (Level-order): ";
    levelOrderTraversal(root);
    cout << endl;

    return 0;
}

9.1 示例树结构

程序中创建的二叉树结构如下:

      1
    /   \
  2     3
  / \   / \
 4   5 6   7

9.2 输出结果

运行以上代码后,输出结果如下:

前序遍历 (Pre-order): 1 2 4 5 3 6 7
中序遍历 (In-order): 4 2 5 1 6 3 7
后序遍历 (Post-order): 4 5  6 7 3 1
层次遍历 (Level-order): 1 2 3 4 5 6 7

相关文章:

  • mysql数据被误删的恢复方案
  • vs2022支持.netframework4.0
  • C++之线程
  • phpipam1.7安装部署
  • 语义源的速率-失真特征(Rate-Distortion Characteristics of Semantic Sources)在语义通信中的理论分析
  • vue3搭建实战项目笔记二
  • 【开源免费】基于SpringBoot+Vue.JS教师工作量管理系统(JAVA毕业设计)
  • arm linux下的中断处理过程。
  • Uniapp中使用Vue3开发微信小程序的全局状态管理实践
  • 【一文读懂】WebRTC协议
  • Ai人工智能的未来:趋势、挑战与机遇
  • leetcode刷题第十天——栈与队列Ⅱ
  • “RAG界的deepseek”开源-企业复杂私域知识理解与推理框架PIKE-RAG
  • 高精度算法
  • 用大模型学大模型03-数学基础 概率论 最大似然估计(MLE)最大后验估计(MAP)
  • 几款C#开发的入门书籍与视频教程
  • LLaMA-Factory 安装linux部署conda笔记
  • MT6835 21位 磁编码器 SPI 平台无关通用驱动框架 STM32
  • DeepSeek教unity------MessagePack-06
  • 【前端如何实现图片懒加载?】
  • “五一”假期首日:国铁南宁局发送旅客81.7万人次
  • 今年4月上海一二手房成交面积同比增21%,二手房成交2.07万套
  • 此前显示售罄的火车票“五一”前大量放出来了?12306回应
  • 耶路撒冷发生山火,以防长宣布紧急状态
  • 济南高新区一季度GDP增长8.5%,第二产业增加值同比增长14.4%
  • 上海市十六届人大常委会第二十一次会议表决通过有关人事任免事项