满二叉树和完全二叉树

满二叉树:叶子节点全都在最底层,除了叶子节点之外,每个节点都有左右两个子节点

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

为什么区分完全二叉树

要理解完全二叉树定义的由来,我们需要先了解,如何表示(或者存储)一棵二叉树?

除了常见的通过指针串联起左右子节点的链式存储法,二叉树还可以用数组存储。如下图

我们把根节点存储在下标 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 的位置),这样就可以通过下标计算,把整棵树都串起来。

而对于普通二叉树,会浪费数组中的部分空间,而完全二叉树不会浪费。所以,如果某棵二叉树是一棵完全二叉树,那用数组存储无疑是最节省内存的一种方式。

<aside> 💡 堆其实就是一种完全二叉树,最常用的存储方式就是数组。

</aside>

支持重复数据的二叉查找树

前面我们讲的二叉查找树的操作,针对的都是不存在键值相同的情况。那如果存储的两个对象键值相同,这种情况该怎么处理呢?我这里有两种解决方法。