2-3 查找树
定义:
一棵 2-3 查找树 或为一棵空树,或由以下结点组成:
2-结点: 含有一个键(及其对应的值)和两条链接,左链接指向的 2-3 树中的键都小于该结点,右链接指向的 2-3 树中的键都大于该结点。
3-结点: 含有两个键(及其对应的值)和三条链接,左链接指向的 2-3 树中的键都小于该结点,中链接指向的 2-3 树中的键都位于该结点的两个键之间,右链接指向的 2-3 树中的键都大于该结点。
将指向一棵空树的链接称为空链接
查找
要判断一个键是否在树中,我们先将它和根结点中的键比较。
如果它和其中任意一个相等,查找命中;
否则我们就根据比较的结果找到指向相应区间的链接,并在其指向的子树中递归地继续查找。
如果这是个空链接,查找未命中。
向 2-结点中插入新键
要在 2-3 树中插入一个新结点,我们可以和二叉查找树一样先进行一次未命中的查找,然后把新结点挂在树的底部。但这样的话树无法保持完美平衡性。
我们使用 2-3 树的主要原因就在于它能够在插入后继续保持平衡。
如果未命中的查找结束于一个 2- 结点,事情就好办了:我们只要把这个 2- 结点替换为一个 3- 结点,将要插入的键保存在其中即可
向一棵只含有一个 3- 结点的树中插入新键
在考虑一般情况之前,先假设我们需要向一棵只含有一个 3- 结点的树中插入一个新键。
这棵树中有两个键,所以在它唯一的结点中已经没有可插入新键的空间了。
为了将新键插入,我们先临时将新键存入该结点中,使之成为一个 4- 结点 。
它很自然地扩展了以前的结点并含有 3 个键和 4 条链接。
创建一个 4- 结点很方便,因为很容易将它转换为一棵由 3 个 2- 结点组成的 2-3 树,其中一个结点(根)含有中键,一个结点含有 3 个键中的最小者(和根结点的左链接相连),一个结点含有 3 个键中的最大者(和根结点的右链接相连)。
这棵树既是一棵含有 3 个结点的二叉查找树,同时也是一棵完美平衡的 2-3 树,因为其中所有的空链接到根结点的距离都相等。
插入前树的高度为 0,插入后树的高度为 1。这个例子很简单但却值得学习,它说明了 2-3 树是如何生长的
向一个父结点为 2- 结点的 3- 结点中插入新键
假设未命中的查找结束于一个 3- 结点,而它的父结点是一个 2- 结点。在这种情况下我们需要在维持树的完美平衡的前提下为新键腾出空间 。我们先像刚才一样构造一个临时的 4- 结点并将其分解,但此时我们不会为中键创建一个新结点,而是将其移动至原来的父结点中。
你可以将这次转换看成将指向原 3- 结点的一条链接替换为新父结点中的原中键左右两边的两条链接,并分别指向两个新的 2- 结点。
根据我们的假设,父结点中是有空间的:父结点是一个 2- 结点(一个键两条链接),插入之后变为了一个 3- 结点(两个键 3 条链接)。另外,这次转换也并不影响(完美平衡的)2-3 树的主要性质。树仍然是有序的,因为中键被移动到父结点中去了;树仍然是完美平衡的,插入后所有的空链接到根结点的距离仍然相同。
请确认你完全理解了这次转换——它是 2-3 树的动态变化的核心
向一个父结点为 3- 结点的 3- 结点中插入新键
现在假设未命中的查找结束于一个父结点为 3- 结点的结点。我们再次和刚才一样构造一个临时的 4- 结点并分解它,然后将它的中键插入它的父结点中。但父结点也是一个 3- 结点,因此我们再用这个中键构造一个新的临时 4- 结点,然后在这个结点上进行相同的变换 ,即分解这个父结点并将它的 中键插入到它的 父结点中去。
推广到一般情况,我们就这样一直向上不断分解临时的 4- 结点并将中键插入更高层的父结点,直至遇到一个 2- 结点并将它替换为一个不需要继续分解的 3- 结点,或者是到达 3- 结点的根。