二叉树的下一个结点
方法一:很简单,从给定的结点node开始向上遍历父节点,直到找到这棵二叉树的根结点root,然后中序遍历这棵二叉树root,每遍历一个结点都与node进行比较,看是否是node,当遇到node后,它的下一个结点就是node的后继结点。这个方法很简单但是向上遍历node之前的所有结点再进行中序遍历,麻烦,因此应该改进。
方法二:利用中序遍历时的结点之间的特点来找到下一个结点。所谓的下一个结点即后序结点是相对于中序遍历而言的,即只有在中序遍历中才有后序结点的概念。要找出一个结点的中序遍历中的下一个结点,就要挖掘在中序遍历中结点之间的关系是怎么样的,在中序遍历中已知一个结点如何和找到它的下一个节点。分析中序遍历后可以发现,对于不同的结点node,它的后序结点的求法是不同的:
情况1:如果node有右子树,那么node的后继结点就是node的右子树上最左的结点,例如结点⑥的后继结点就是⑦;
情况2:如果node没有右子树,并且它有父节点(如果node没有右子树且没有父节点那么node就是根结点并且没有右子树,于是它的后继结点就是null),并且node是父节点的左结点,那么node的父节点就是node的后继结点。例如结点⑤的后继结点就是⑥。
情况3:如果node没有右子树,并且node是父节点的右结点,例如③,那么它的后继结点比较复杂:一直向上遍历它的父节点node=node.parent,当某个结点node是它父节点的左结点时,即node=node.parent.left时,那么此时这个父节点node.parent就是node的后继结点。如果一直向上遍历node都不存在node是其父节点的左结点,即当node=node.parent等于null时还不满足,那么说明结点node是中序遍历的最后一个结点,后继结点为null。
只有以上3中情况,对输入的node进行逐一分析和处理即可。在分析问题时可以先画出一棵具有中序遍历顺序的二叉树,然后最不同结点的情况进行不同的分析即可,画图可以使得问题易于分析
/*
注意这里的结点的定义比较特殊,不要惯性思维
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
千万注意:这里父节点用next而不是parent来表示
TreeLinkNode(int val) {
this.val = val;
}
}
*/
//给出一个结点,找出这个结点在后序遍历中的下一个结点:分析可以,后继结点只可能来自3中情况
publicclass Solution {
public TreeLinkNode GetNext(TreeLinkNodepNode){
if(pNode.right!=null){
//情况1:有右子树,后继结点是右子树上的最左端结点
TreeLinkNode temp=pNode.right;
while(temp.left!=null){
temp=temp.left;
}
return temp;
}else if(pNode.next==null){
//情况2:没有右子树且pNode没有父节点,则后继结点是null
return null;
}else if(pNode==pNode.next.left){
//情况2:没有右子树且pNode有父节点且pNode是父节点的左结点,则后继结点就是父节点
return pNode.next;
}else{
//情况3:没有右子树且pNode是父节点的右子树,则后继结点是向上作为左孩子的父节点
TreeLinkNode temp=pNode;
TreeLinkNode tempParent=pNode.next;
while(tempParent!=null){
if(temp==tempParent.left)return tempParent;
temp=tempParent;
tempParent=tempParent.next;
}
//执行到此还没有返回说明没有后继结点
return null;
}
}
}