首先,我们要明白什么是线索化二叉树?
线索化二叉树:
是利用二叉树的链式存储结构中存在的空指针,
利用这些空指针指向二叉树遍历序列的前驱或后继元素,
以便于加快遍历和查找结点的速度。
那么接下来~我们就要总结一下关于线索化二叉树的豆知识啦
Q1:在线索化二叉树当中,能够利用的指针有多少个呢?
A1:首先,我们将Nn表示一颗二叉树中度为n的结点一共有N个。总结点数有M个。空指针数量有P个
所以我们可以得到以下关系
关系式1:N0+N1+N2=M(结点数和)
关系式2:N1+2*N2+1=M(分支数+1等于结点数)
关系式3:N1+2N0=P(度为一的结点有一个空指针,度为0的结点有2个空指针)。
联立关系式1和2,我们不难得出2N0+N1=M+1。
所以在线索化二叉树中可以利用的指针有M+1个
Q2:如何将一棵树转化成线索化二叉树呢?
A2:代码片如下:
/**递归调用将某二叉树变为中序遍历线索化二叉树
* @param presentNode 该参数结点为当前结点
* @param pirorNode 该参数结点为当前结点在中序遍历序列中的前驱结点
* */
void BuildThreadBTree(TreeNode presentNode,TreeNode pirorNode){
if(presentNode!=null){
BuildThreadBTree(presentNode.lChild,pirorNode);
//从根节点开始对当前结点的左子树进行线索化操作
if(presentNode.lChild==null){
presentNode.lChild=pirorNode;
presentNode.lTag=1;
//如果该结点的左子树为空,则指向前驱并设置tag
}
if(pirorNode!=null && pirorNode.lChild==null){
pirorNode.rChild=presentNode;
pirorNode.rTag=1;
//如果前驱结点不为空并且前驱结点的又孩子为空,则前驱结点的右孩子指向当前结点并设置tag。
}
pirorNode=presentNode;
//移动指针,前驱结点指向线索完成的当前结点,要注意的是由于在对根节点进行操作时,根节点的前驱结点为空
BuildThreadBTree(presentNode.rChild, pirorNode);
//递归对右子树进行线索化操作。
}
}
void CreatTree(TreeNode T){
TreeNode piror=null;
if(T!=null){
BuildThreadBTree(T, piror);
piror.lChild=null;
piror.rTag=1;
//最后两个语句是为了处理最后一个结点
}
}
关于这段代码,还有几个值得注意的地方
1:使用线索化左子树->操作根节点->线索化右子树的操作顺序是为了对应中序遍历。
2:往前驱结点的右指针填入当前结点而不是往当前结点的右指针填写当前结点的后继是因为……参数表只传入了前驱和当前结点
(我认为如果参数表有3个的话应该可以实现将后继填)