【白话树】之 二叉树

一、二叉树的基本概念

1、 二叉树定义

二叉树:是一种非线性数据结构,是“分而治之”思想的一种实现。

和链表一样,二叉树最基本的单位也是节点。

只是二叉树的节点,不仅包含值本身,也包含了左子节点和右子节点的引用。

二叉树(binary tree)是n(n≥0)个节点构成的集合,它或为空树(n=0)​,或满足以下两个条件:

1)有且仅有一个称为根的节点

2)除根节点以外,其余节点分为两个互不相交的子集T1和T2,分别称为T的左子树和右子树,且T1和T2本身都是二叉树

二叉树是一种特殊的树,它最多有两个子树,分别为左子树和右子树,二者是有序的,不可以互换。

也就是说,二叉树中不存在度大于2的节点。

下面是二叉树的五种形态:
在这里插入图片描述

Java结构代码:

/* 二叉树节点类 */
class TreeNode {
    int val;         // 节点值
    TreeNode left;   // 左子节点引用
    TreeNode right;  // 右子节点引用
    TreeNode(int x) { val = x; }
}

2、常见术语

  • 根节点:二叉树顶层的节点,唯一没有父节点的节点
  • 叶子节点:没有子节点的节点
  • 边:两个节点之间的连线
  • 节点所在的层:根节点层数为1,相当于根节点的层数 + 节点到根的边数
  • 节点的度子节点的数量
  • 二叉树的高度:根节点到所有叶子节点的最大的边数
  • 节点的深度根节点到节点的边数
  • 节点的高度节点到所有叶子节点的最大的边数
    在这里插入图片描述

3、基本操作

1)创建:

Java实现:

// 初始化节点
TreeNode n1 = new TreeNode(1);
TreeNode n2 = new TreeNode(2);
TreeNode n3 = new TreeNode(3);
TreeNode n4 = new TreeNode(4);
TreeNode n5 = new TreeNode(5);
// 构建节点之间的引用(指针)
n1.left = n2;
n1.right = n3;
n2.left = n4;
n2.right = n5;

2)插入与删除:

在这里插入图片描述
Java实现:

TreeNode P = new TreeNode(0);
// 在 n1 -> n2 中间插入节点 P
n1.left = P;
P.left = n2;
// 删除节点 P
n1.left = n2;

4、常见类型

1)满二叉树(完美二叉树)

所有层的节点都被填满的二叉树。
在这里插入图片描述

2)完全二叉树

只有最底层的节点没有被填满,而且同一层级是从左到右依次填充的。
在这里插入图片描述

3)完满二叉树

除了叶节点之外,其余所有节点都有两个子节点。
在这里插入图片描述

4)平衡二叉树

任意节点的左子树和右子树的高度之差的绝对值不超过 1 。
在这里插入图片描述

5)链表 - 特殊的二叉树

当二叉树中的每一层只有一个节点的时候,所有的节点组成一个链表。

二、二叉树遍历

1、层序遍历

相关概念: 广度优先遍历、广度优先搜索/BFS

遍历方式: 自顶向下,从左到右,逐层遍历

图示:
在这里插入图片描述
Java代码实现:

/* 层序遍历 */
List<Integer> levelOrder(TreeNode root) {
    // 初始化队列,加入根节点
    Queue<TreeNode> queue = new LinkedList<>();
    queue.add(root);
    // 初始化一个列表,用于保存遍历序列
    List<Integer> list = new ArrayList<>();
    while (!queue.isEmpty()) {
        TreeNode node = queue.poll(); // 队列出队
        list.add(node.val);           // 保存节点值
        if (node.left != null)
            queue.offer(node.left);   // 左子节点入队
        if (node.right != null)
            queue.offer(node.right);  // 右子节点入队
    }
    return list;
}

2、前序、中序、后序遍历

相关概念: 深度优先遍历、深度优先搜索/DFS

快速记忆: 先走到尽头,再回溯继续。

  • 前序(根节点 -> 左子树 -> 右子树)
  • 中序(左子树 -> 根节点 -> 右子树)
  • 后序(左子树 -> 右子树 -> 根节点)

图示:
在这里插入图片描述
深度优先遍历就像是绕着整棵二叉树的外围“走”一圈

深度优先搜索通常基于递归实现,Java代码如下:

/* 前序遍历 */
void preOrder(TreeNode root) {
    if (root == null)
        return;
    // 访问优先级:根节点 -> 左子树 -> 右子树
    list.add(root.val);
    preOrder(root.left);
    preOrder(root.right);
}

/* 中序遍历 */
void inOrder(TreeNode root) {
    if (root == null)
        return;
    // 访问优先级:左子树 -> 根节点 -> 右子树
    inOrder(root.left);
    list.add(root.val);
    inOrder(root.right);
}

/* 后序遍历 */
void postOrder(TreeNode root) {
    if (root == null)
        return;
    // 访问优先级:左子树 -> 右子树 -> 根节点
    postOrder(root.left);
    postOrder(root.right);
    list.add(root.val);
}

参考资料:

《趣学数据结构》 – 陈小玉
https://www.hello-algo.com/chapter_tree/binary_tree/#4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Coder.Ren

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值