二叉树学习笔记

二叉树基础知识

二叉树是计算机科学中一种非常重要的数据结构,它广泛应用于各种算法和应用中。以下是二叉树的一些基本知识:

  1. 定义

    • 二叉树是每个节点最多有两个子树的树结构,通常称为“左子树”和“右子树”。
  2. 节点

    • 每个节点包含三个部分:一个数据元素和两个指针(或链接),分别指向左右子树。
  3. 根节点

    • 二叉树只有一个根节点,它是树的顶部节点,没有父节点。
  4. 叶子节点

    • 如果一个节点没有左子树或右子树,或者两者都没有,那么它被称为叶子节点。
    • 一个节点的度是指它拥有的子树数量。在二叉树中,节点的度可以是0(叶子节点)、1或2。
  5. 高度和深度

    • 二叉树的高度是从根节点到最远叶子节点的最长路径上的节点数。
    • 节点的深度是它到根节点的路径上的节点数,包括根节点和该节点本身。
  6. 满二叉树

    • 所有层都被完全填满的二叉树,除了最后一层,最后一层从左到右填满。
  7. 完全二叉树

    • 除了最后一层外,每一层都被完全填满,并且最后一层的节点都尽可能地靠左排列。
  8. 平衡二叉树

    • 任何节点的两个子树的高度差不超过1。
  9. 二叉搜索树(BST)

    • 一种特殊的二叉树,其中每个节点的值都大于其左子树中的任何节点的值,并且都小于其右子树中的任何节点的值。
  10. 遍历

    • 遍历二叉树是指按照某种顺序访问树中的每个节点的过程。常见的遍历方法包括:

深度优先遍历

  - 前序遍历(Pre-order)
  - 中序遍历(In-order)
  - 后序遍历(Post-order)

这里前中后,其实指的就是中间节点的遍历顺序,只要记住前中后序指的就是中间节点的位置就可以了。

广度优先遍历

  - 层序遍历(Level-order)
  1. 操作

    • 在二叉树上执行的操作包括搜索、插入、删除节点等。
  2. 应用

    • 二叉树在许多领域都有应用,如文件系统、数据库索引、表达式树、决策树、二叉堆等。

二叉树的这些基本概念是理解和实现更复杂数据结构和算法的基础。

二叉树的种类

二叉树分为两个大类:满二叉树(Full Binary Tree)和完全二叉树(Complete Binary Tree)。

满二叉树

在这里插入图片描述

如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
这棵二叉树为满二叉树,也可以说深度为k,有2^k-1个节点的二叉树

完全二叉树

在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层(h从1开始),则该层包含 1~ 2^(h-1) 个节点,也就是说满二叉树是特殊的完全二叉树。
在这里插入图片描述

二叉搜索树

若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉排序树
在这里插入图片描述

平衡二叉搜索树

平衡二叉搜索树:又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
在这里插入图片描述

二叉树的链式存储定义

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

int val:存储节点的值。
TreeNode *left:指向该节点左子树的指针。
TreeNode *right:指向该节点右子树的指针。

此外,还定义了一个构造函数TreeNode(int x),它初始化节点的值val为参数x,并将左右子树的指针初始化为NULL,表示新创建的节点最初没有子节点。

这个结构体是二叉查找树节点的标准表示方式,可以用于实现二叉查找树的各种操作,如插入、删除、查找等。

二叉树链式存储基本操作示例

#include <iostream>

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

// 函数用于插入新节点
void insert(TreeNode*& root, int val) {
    if (root == NULL) {
        root = new TreeNode(val);
    } else if (val < root->val) {
        insert(root->left, val);
    } else {
        insert(root->right, val);
    }
}

// 函数用于打印二叉树(中序遍历)
void inorder(TreeNode* root) {
    if (root != NULL) {
        inorder(root->left);
        std::cout << root->val << " ";
        inorder(root->right);
    }
}

int main() {
    TreeNode* root = NULL;
    insert(root, 5);
    insert(root, 3);
    insert(root, 7);
    insert(root, 2);
    insert(root, 4);
    insert(root, 6);
    insert(root, 8);

    std::cout << "Inorder traversal of the binary search tree: ";
    inorder(root);
    std::cout << std::endl;

    return 0;
}

二叉树顺序存储

二叉树的顺序存储是指使用数组来存储二叉树的结构。在顺序存储中,二叉树的节点按照一定的顺序存储在数组中,这样可以通过节点在数组中的索引来确定节点之间的关系。

顺序存储的规则

对于一个有 ( n ) 个节点的二叉树,假设节点按照层序遍历(从上到下,从左到右)的方式存储在数组中,那么对于数组中任意位置 ( i ) 的节点,它在数组中的左子节点和右子节点的位置可以通过以下规则确定:

  • 左子节点的位置:( 2i + 1 )
  • 右子节点的位置:( 2i + 2 )

特点

  1. 空间利用:顺序存储可以高效地利用计算机内存,因为它避免了指针或链接的使用,从而节省了存储指针的空间。
  2. 简单性:实现简单,不需要复杂的指针操作。
  3. 限制:顺序存储要求预先知道树的最大大小,因此在实际应用中可能不够灵活。

示例

假设我们有一个二叉树,其节点按照层序遍历的顺序存储在数组中如下:

    A
   / \
  B   C
 / \   \
D   E   F

存储在数组中的顺序为:A, B, C, D, E, F

  • 节点 A 的左子节点是 B(位置 1),右子节点是 C(位置 2)。
  • 节点 B 的左子节点是 D(位置 3),右子节点是 E(位置 4)。

应用

顺序存储的二叉树常用于实现二叉堆,特别是在实现优先队列时。在二叉堆中,父节点和子节点之间的关系是固定的,这使得顺序存储成为可能。

注意事项

  • 当使用顺序存储时,通常需要一个额外的变量来记录树中节点的数量,因为数组的大小是固定的。
  • 在删除操作中,需要移动节点以保持数组的连续性,这可能会增加操作的复杂性。

顺序存储是二叉树存储的一种有效方式,尤其适用于节点数量固定或已知的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值