数据结构 - 树

本文介绍了树的相关概念,包括节点的深度、高度和层数。接着详细讲解了二叉树,特别是链式存储法和顺序存储法,以及二叉树的遍历。然后深入探讨了二叉查找树(Binary Search Tree),包括查找、插入和删除操作,以及在不同形态下的时间复杂度分析。最后,对比了二叉查找树相对于散列表的优势。
摘要由CSDN通过智能技术生成

(1)相关概念

兄弟节点:节点的父节点是同一个节点,所以它们之间互称为兄弟节点。

根节点:没有父节点的节点叫作根节点

叶子节点:没有子节点的节点叫作叶子节点或者叶节点。

节点的高度:节点到叶子节点的最长路径(边数)。

节点的深度:根节点到这个节点所经历的边的个数。

节点的层数:节点的深度 + 1.

树的高度:根节点的高度。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G7MY1WWx-1585234305704)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1585227146916.png)]

记这几个概念,还有一个小窍门,就是类比“高度”、“深度”、“层”这几个名词在生活中的含义。

在生活中,“高度”这个概念,其实就是从下往上度量,比如要度量第 10 层楼的高度、第 13 层楼的高度,起点都是地面。所以,树这种数据结构的高度也是一样,从最底层开始计数,并且计数的起点是 0。

“深度”这个概念在生活中是从上往下度量的,比如水中鱼的深度,是从水平面开始度量的。所以,树这种数据结构的深度也是类似的,从根结点开始度量,并且计数起点也是 0。

“层数”跟深度的计算类似,不过,计数起点是 1,也就是说根节点的位于第 1 层。

(2)二叉树(Binary Tree)

二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子节点右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只有左子节点,有的节点只有右子节点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lvvxBsdg-1585234305711)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1585228609837.png)]
编号 2 的二叉树中,叶子节点全都在最底层,除了叶子节点之外,每个节点都有左右两个子节点,这种二叉树就叫作满二叉树

编号 3 的二叉树中,叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大,这种二叉树叫作完全二叉树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-10nrulvD-1585234305731)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1585228784320.png)]
存储一棵二叉树,我们有两种方法,一种是基于指针或者引用的二叉链式存储法,一种是基于数组的顺序存储法。

1. 链式存储法

每个节点有三个字段,其中一个存储数据,另外两个是指向左右子节点的指针。

只要拎住根节点,就可以通过左右子节点的指针,把整棵树都串起来。这种存储方式我们比较常用。大部分二叉树代码都是通过这种结构来实现的。
在这里插入图片描述

2. 顺序存储法

把根节点存储在下标 i = 1 的位置,那左子节点存储在下标 2 * i = 2 的位置,右子节点存储在 2 * i + 1 = 3 的位置。以此类推,B 节点的左子节点存储在 2 * i = 2 * 2 = 4 的位置,右子节点存储在 2 * i + 1 = 2 * 2 + 1 = 5 的位置。

如果节点 X 存储在数组中下标为 i 的位置,下标为 2 * i 的位置存储的就是左子节点,下标为 2 * i + 1 的位置存储的就是右子节点。反过来,下标为 i/2 的位置存储就是它的父节点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S9tbQpEM-1585234305739)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1585229609566.png)]

不过,上面的例子是一棵完全二叉树,所以仅仅“浪费”了一个下标为 0 的存储位置。如果是非完全二叉树,其实会浪费比较多的数组存储空间。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yKrpZ94D-1585234305742)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1585229773296.png)]

所以,如果某棵二叉树是一棵完全二叉树,那用数组存储无疑是最节省内存的一种方式。因为数组的存储方式并不需要像链式存储法那样,要存储额外的左右子节点的指针。这也是为什么完全二叉树会单独拎出来的原因,也是为什么完全二叉树要求最后一层的子节点都靠左的原因。

3. 二叉树的遍历

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l4xZpmmi-1585234305747)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1585232103561.png)]
经典的方法有三种,前序遍历中序遍历后序遍历

  • 前序遍历是指,对于树中的任意节点来说,先打印这个节点,然后再打印它的左子树,最后打印它的右子树。

    preOrderTraverse(callback) {
         
        const preOrderTraverseNode = (node, callback) => {
         
            if (node !== null) {
         
                callback(node.key)
                preOrderTraverseNode(node.left, callback)
                preOrderTraverseNode(node.right, callback)
            }
        }
        preOrderTraverseNode(this.root, callback)
    }
    tree.inOrderTraverse(value => {
          console.log(value) })<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值