简单二叉树

本文介绍了二叉树的概念,包括为何使用树结构,树的常用术语,以及二叉树的特性。重点讲解了二叉树的前序、中序、后序遍历,节点查找及删除的操作。通过对示例二叉树的演示,阐述了遍历、查找和删除的实现思路及代码实现。
摘要由CSDN通过智能技术生成

一、二叉树概述

1.1 为什么要有树这种数据结构

在前面已经学习了数组和链表这两种数据结构,这两种数据结构都有着鲜明的特点。

数组存储方式的优缺点如下:

  • 优点:通过下标方式访问元素,速度快。对于有序数组,还可使用二分查找提高检索速度。
  • 缺点:如果要检索具体某个值,或者插入值(按一定顺序)会整体移动, 效率较低。

链表存储方式的优缺点如下:

  • 优点:在一定程度上对数组存储方式有优化。比如插入一个数值节点,只需要将插入节点链接到链表中即可,其删除效率也较高。
  • 缺点:在进行检索时,效率仍然较低。比如检索某个值, 需要从头节点开始遍历。

从它们的特点我们可以总结出:数组方式查找快、增删慢,而链表方式查找慢、增删快。这两种数据存储方式都相当于是鱼与熊掌不可兼得。

而树这种数据结构,可以在查找速度快的同时又兼顾了增删的效率,可以说是结合了数组和链表的优点

树存储方式的核心特点为:能提高数据存储、读取的效率。比如利用二叉排序树(Binary Sort Tree),既可以保证数据的检索速度,同时也可以保证数据的插入、删除、修改的速度。

在这里插入图片描述

1.2 树的常用术语

树这种数据结构有较多的常用术语,这些术语我们需要熟练记住。

在这里插入图片描述

这些常用术语包括:

  1. 节点
  2. 根节点
  3. 父节点
  4. 子节点
  5. 叶子节点(没有子节点的节点)
  6. 节点的权(节点值)
  7. 路径(从 root 节点找到该节点的路线)
  8. 子树
  9. 树的高度(最大层数)
  10. 森林(多颗子树构成森林)

常用术语虽然比较多,但是对照着树的示意图,还是比较容易理解的。

1.3 什么是二叉树

树有很多种,每个节点最多只能有两个子节点的一种形式称为二叉树。二叉树的子节点分为左节点和右节点。

在这里插入图片描述

如上图所示的三个树,它们每个节点最多只有两个子节点,因此它们都是二叉树。

在二叉树中,还有两种更为特殊的树,分别是:

  • 满二叉树

    如果二叉树的所有叶子节点都在最后一层,并且结点总数= 2^n -1 , n 为层数,则我们称其为满二叉树。

    在这里插入图片描述

  • 完全二叉树

    如果二叉树的所有叶子节点都在最后一层或者倒数第二层,而且最后一层的叶子节点在左边(相对于根节点)连续,倒数第二层的叶子节点在右边连续,我们称为完全二叉树。

    在这里插入图片描述

我们不难看出:满二叉树是完全二叉树的特殊形态, 即如果一棵二叉树是满二叉树, 则它必定是完全二叉树

1.4 二叉树的遍历顺序

二叉树的遍历共有三种情况:

  • 前序遍历

    先遍历根节点,再遍历左子树,最后遍历右子树。

  • 中序遍历

    先遍历左子树,再遍历根节点,最后遍历右子树。

  • 后序遍历

    先遍历左子树,再遍历右子树,最后遍历根节点。

根据这三种遍历顺序的定义,我们可以得知两个结论:

  1. 左子树总是在右子树的前面遍历;
  2. 前、中、后的遍历顺序指的是遍历根节点的顺序。

二、二叉树的基本操作

本节的关于二叉树的操作,都是对如下图所示的二叉树进行的:

在这里插入图片描述

如上所示的二叉树,每一个节点都是一个英雄节点 HeroNode ,每个节点记录着英雄的信息(编号、姓名)。

英雄节点模型如下:

/**
 * 模拟二叉树的节点
 */
class HeroNode{
   
    public int no;
    public String name;
    public HeroNode left;   // 左子节点
    public HeroNode right;  // 右子节点

    public HeroNode(int no, String name){
   
        this.no = no;
        this.name = name;
    }    
    // 添加左子节点
    public void addLeftNode(HeroNode node){
   
        this.left = node;
    }
    // 添加右子节点
    public void addRightNode(HeroNode node){
   
        this.right = node;
    }
    // ......
    
    @Override
    public String toString() {
   
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}

除此之外,我们还需要创建一个二叉树模型 BinaryTree,包含对二叉树的操作:

class BinaryTree{
   
    private HeroNode root;  // 根节点

    public BinaryTree(HeroNode node){
   
        this.root = node;
    }
    // ......
}

为了方便后续的代码测试,我们手动创建一个上图所示的二叉树:

HeroNode node_1 = new HeroNode(1, "宋江");
HeroNode node_2 = new HeroNode(2, "卢俊义");
HeroNode node_3 = new HeroNode(3, "吴用");
HeroNode node_4 = new HeroNode(4, "公孙胜");
HeroNode node_5 = new HeroNode(5, "关胜");

BinaryTree binaryTree = new BinaryTree(node_1);
node_1.addLeftNode(node_2);
node_1.addRightNode(node_3);
node_3.addLeftNode(node_4);
node_3.addRightNode(node_5);

2.1 二叉树的节点遍历

【案例需求】

使用前序、中序、后序分别遍历二叉树。

【思路分析】

上面说过,二叉树的遍历包括:前序遍历、中序遍历、后序遍历。

其中前序遍历的思路如下:

  1. 首先输出当前节点;
  2. 如果左子节点不为空,就对左子节点递归前序遍历;
  3. 如果右子节点不为空,就对右子节点递归前序遍历。

中序遍历的思路如下:

  1. 首先判断左子节点是否为空,如果不为空,就对左子节点递归中序遍历;
  2. 然后输出当前节点;
  3. 最后判断右子节点是否为空,如果不为空,就对右子节点递归中序遍历。

后序遍历的思路如下:

  1. 首先判断左子节点是否为空,如果不为空,就对左子节点递归后序遍历;
  2. 然后判断右子节点是否为空,如果不为空,就对右子节点递归后序遍历;
  3. 最后输出当前节点。

【代码实现】

英雄节点 HeroNode 负责对子树的具体操作,二叉树 BinaryTree 调用节点的具体操作来实现相关操作。

二叉树的遍历操作实现代码如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值