中序遍历:
一:找二叉树最左侧节点。在寻找二叉树最左侧节点的过程中对于每一个根节点(为什么称每一个根节点呢?因为子树也具有根节点)都构建其前驱节点。
中序遍历时每个根节点的前驱节点怎么找呢?———每个根节点的左子树的最右侧节点即为其前驱,找到前驱节点后将前驱结点的右指针指向该根节点。(构建前驱节点的过程有构建线索二叉树的味道)
二:判断是否访问输出节点。当前节点记为cur,cur节点作为根的左子树的最右侧节点记为right。
如果cur没有左子树则输出cur的值,并使得cur=cur->right;重复二
若cur有左子树则判断该左子树的right的右指针是否指向cur
①若right的右指针指向cur,则说明已经经历过一(即已经构建了前驱线索),此时访问输出cur,并将right的右指针置为null(拆除线索的意思),并使得cur=cur->right;重复二
②若right的右指针为null,则说明未经历过一(即说明现在到了整个二叉树的右子树,该右子树还未创建前驱线索),此时进入一
“一”可认为是从上向下走,“二”可认为是从下往上回
void morrisMiddle(TreeNode *head){
TreeNode *p1=head;
TreeNode *p2=NULL;
while(p1!=NULL){
p2=p1->left;
if(p2!=NULL){ //p1的左子树不为空时
while(p2->right!=NULL&&p2->right!=p1)//在p1的左子树中,一直探索至最右侧节点
p2=p2->right;
if(p2->right==NULL){ //探索到最右侧节点,如果右指针的指向为空,则是“一”
p2->right=p1;
p1=p1->left;
continue;
}else{ //探索到最右侧节点,这种情况为最右侧节点的右指针指向p1,即已经构建好线索
cout<<p1->val;
p1=p1->right;
p2->right=NULL; //为什么可以在此处将线索取消呢,因为若执行到这一步的话,该线索已经被42行使用过
}
}else{
//p1的左子树为空时以及
cout<<p1->val;
p1=p1->right;
}
}
}
//也可以这样写
void morrisMiddle(TreeNode *head){
TreeNode *p1=head;
TreeNode *p2=NULL;
while(p1!=NULL){
p2=p1->left;
if(p2!=NULL){ //p1的左子树不为空时
while(p2->right!=NULL&&p2->right!=p1)//在p1的左子树中,一直探索至最右侧节点
p2=p2->right;
if(p2->right==NULL){ //探索到最右侧节点,如果右指针的指向为空,则是“一”
p2->right=p1;
p1=p1->left;
continue;
}else //探索到最右侧节点,这种情况为最右侧节点的右指针指向p1,即已经构建好线索
p2->right=NULL; //为什么可以在此处将线索取消呢,因为若执行到这一步的话,该线索已经被42行使用过
}
//p1的左子树为空时以及
cout<<p1->val;
p1=p1->right;//此处要么正常进入右子树,要么由线索进入某子树的根节点
}
}