1、什么树

首先我们要知道,树是一种非线性表结构。通过下面的图我们可以更加直观的了解到什么是树。

数据结构与算法——二叉树(上)

通过上面的图我们可以发现,“树”这种数据结构和我们现实生活中的树很像。上图中的每一个元素我们称之为“节点”;用来连接相邻节点之间的关系,我们叫作“父子关系”。

如下图所示,A节点就是B节点的父节点,B节点是A节点的子节点。B、C、D这三个节点的父节点是同一个节点,所以它们之间互称为兄弟节点。我们把没有父节点的节点叫作根节点,也就是图中节点E。我们把没有子节点的节点叫作叶子节点或者叶节点,比如图中G、H、I、J、K、L都是叶子节点。

数据结构与算法——二叉树(上)

  除此之外,关于“树”,还有三个比较重要的概念:高度深度。它们的定义是这样的:

(1)节点的高度 = 节点到叶子节点最长路径。(即以叶子节点为基准)

(2)节点的深度 = 跟节点到这个节点所经历的边的个数。(即以根节点为基准)

(3)节点的层数 = 节点的深度 + 1.

(4)树的高度 = 根节点的高度。

下面的图可以更好的帮助我们理解这三个概念

数据结构与算法——二叉树(上)

 2、二叉树

树结构多种多样,不过我们最常用的还是二叉树。

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

数据结构与算法——二叉树(上)

 这个图里面,有两个比较特殊的二叉树,分别是编号2和编号3这两个。

其中编号2的二叉树中,叶子节点全都在最底层,除了叶子节点之外,每个节点都有左右两个子节点,这种二叉树就叫作满二叉树

编号3的二叉树中,叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大,这个二叉树叫作完全二叉树

总结如下:

1、满二叉树

(1)所有的叶子节点都在最后一层。

(2)除了叶子节点之外,每个节点都有左右两个子节点。

2、完全二叉树

(1)叶子节点只在最后两层出现。

(2)最后一层的叶子节点优先靠左排列。

(3)除了最后一层之外,其他层的节点个数达到最大。

通过下面的图可以帮助我们进一步的了解完全二叉树。

数据结构与算法——二叉树(上)

 通过上面的介绍,我们知道了什么是棵完全二叉树,但是大家肯定会疑问为什么完全二叉树要这样要求,想要知道这个原因,那么下面就需要了解一下二叉树的存储。

3、二叉树的存储

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 的位置存储就是它的父节点。通过这种方式,我们只要知道根节点存储的位置(一般情况下,为了方便计算子节点,根节点会存储在下标为1的位置),这样就可以通过下标计算,把整棵树都串起来。

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

数据结构与算法——二叉树(上)

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

4、二叉树的遍历

前面介绍了二叉树的基本定义和存储方法,现在我们来看二叉树中非常重要的操作,二叉树的遍历。

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

(2)中序遍历:对于树中的任意节点来说,先打印它的左子树,然后再打印它本身,最后打印它的右子树。

(3)后序遍历:对于树中任意节点来说,先打印它的左子树,然后再打印它的右子树,最后打印这个节点本身。

数据结构与算法——二叉树(上)

 实际上,二叉树的前、中、后序遍历就是一个递归的过程。具体的实现,我会在下一篇博文中给出。

从前面画的前、中、后序遍历的顺序图,可以看出来,每个节点最多会被访问两次,所以遍历操作的时间复杂度,跟节点的个数n成正比,也就是说二叉树遍历的时间复杂度是O(n)。

相关文章:

  • 2022-01-11
  • 2022-12-23
  • 2021-11-17
  • 2021-10-12
  • 2021-06-18
  • 2021-07-03
  • 2021-11-22
  • 2021-11-24
猜你喜欢
  • 2022-12-23
  • 2021-09-22
  • 2021-12-08
  • 2022-01-16
  • 2021-04-20
  • 2021-11-13
  • 2021-08-20
相关资源
相似解决方案