中序(前序/后序)线索:
对于n个节点的二叉链表,共有2n个指针域。其中,除根节点外,其余n-1个节点需要占据n-1个指针域。为了合理利用剩余n+1个指针域,我们就将其用于为线索(实际上无法全部利用,第一个节点无前驱,最后一个节点无后继)。
- 如果一个节点 𝑃 有左子树,那么它的左线索将指向它的左孩子。
- 如果一个节点 𝑃 没有左子树,那么它的左线索将指向它的中序(前序/后序)前驱。
- 如果一个节点 𝑃 有右子树,那么它的右线索将指向它的右孩子。
- 如果一个节点 𝑃 没有右子树,那么它的右线索将指向它的中序(前序/后序)后继。
下面讨论不同遍历顺序下线索树中某节点的前驱,后继情况。
1.在后序线索二叉树中查找结点 *p 的前驱:
若结点 *p 无左右子树,这种情况下,后序遍历的前驱有可能是 *p 的父结点或更靠近根部的其他祖先结点。
若结点 *p 有左子树,当其右子树为空时,其左子树的根(即 p->left )为其后序前驱。
当其右子树非空时,其右子树的根(即 p->right )为其后序前驱。
2.在后序线索二叉树中查找结点 *p 的后继:
若结点 *p 为根节点,则无后继;
若结点 *p 为其双亲*r的右孩子,则其后继为其双亲*r;
若结点*p 为其双亲的左孩子,且双亲无右子女,则其后继为其双亲*r;
若结点 *p 为其双亲的左孩子,且双亲有右子女,则结点 *p 的后继是其双亲*r的右子树中按后序遍历的第一个结点(即r右子树往左走到底的节点)。
所以,求后序线索二叉树中结点的后继要知道其双亲的信息。然而,对于树中节点,是容易找到孩子,不易找到非双亲的。因此我们需要使用栈来保存从根到当前节点的访问路径,这样才能方便地回溯到双亲节点。由于要使用栈,所以说后序线索二叉树是不完善的。
3. 在先序线索二叉树中查找结点 *p 的前驱
若结点 p 是根结点:它没有前驱。
若结点 p 不是根结点:
如果 p 是其父结点的左孩子:那么,p 的前驱就是它的父结点。
如果 p 是其父结点的右孩子:在这种情况下,p 的前驱是父结点的“最右后代”。这是因为先序遍历会先访问父结点,再访问左子树,最后访问右子树的所有结点,因此前驱就是左子树的最右结点(如果存在),或者是父结点。
4.在先序线索二叉树中查找结点 *p 的后继:
若结点 *p 有左孩子,则后继为 *p 的左孩子(因为先访问左子树)。
若结点 *p 没有左孩子但有右孩子,则后继为 *p 的右孩子。
若结点 *p 没有子女,则后继需要向上回溯至祖先结点中第一个有右孩子的结点,且该右孩子未被访问过。这个过程需要线索指针。
5.在中序线索二叉树中查找结点 *p 的前驱:
若结点 p 有左子树:
p 的前驱是其左子树中“最右”的结点。换句话说,从 p 的左孩子开始,沿着右指针一直向右移动,直到无法移动为止。
若结点 p 没有左子树:
p 的前驱是一个“向上回溯”的结点,具体来说,它是从 p 向上追溯找到的第一个右孩子的祖先结点(即,在中序遍历中 p 前面被访问的结点)。
6.在中序线索二叉树中查找结点 *p 的后继:
若结点 p 有右子树:
p 的后继是其右子树中“最左”的结点。换句话说,从 p 的右孩子开始,沿着左指针一直向左移动,直到无法移动为止。
若结点 p 没有右子树:
p 的后继是一个“向上回溯”的结点,具体来说,它是从 p 向上追溯找到的第一个左孩子的祖先结点(即,在中序遍历中 p 后面被访问的结点)。
判断题:
- 非空的二叉树一定满足:某节点p若有左孩子,则在中序序列中p的前驱节点一定没有右孩子。
正确。
2.在中序线索树中,每一非空的线索均指向其祖先节点。
正确。
如果是前驱,该线索处的节点是没有左子树的,其线索指向p 向上追溯找到的第一个右孩子的祖先结点。
如果是后继,该线索处的节点是没有右子树的,其线索指向p 向上追溯找到的第一个左孩子的祖先结点。