剑指Offer_编程题——二叉树的下一个结点
题目描述:
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
具体要求:
时间限制: C/C++ 1秒,其他语言2秒
空间限制: C/C++32M,其他语言64M
具体实现:
思路一:
在做题前,我们应该给大家介绍二叉树的中序遍历的相关知识:在前面的文章里给大家介绍过二叉树的遍历。因此,这里就给大家不详细介绍了。现在给大家介绍解题思路:我们根据对二叉树知识的了解,可以将情况分为三种:第一种:有右孩子,找到右孩子,循环遍历右孩子的左节点、第二种:没有右孩子,而且是根的左孩子,返回父亲节点、第三种:是父亲节点的右孩子,而且没有右孩子,则返回父亲节点的父节点等。具体的过程如下图所示:
因此,我们可以使用java来实现该思路:
public class Solution{
public TreeLinkNode GetNext(TreeLinkNode pNode){
if(pNode.right != null){
pNode = pNode.right;
while(pNode.left != null){
pNode = pNode.left;
}
return pNode;
}
while(pNode.next != null && pNode.next.right == pNode){
pNode = pNode.next;
}
return pNode.next;
}
}
代码效果图如图所示:
正如前面说的那样,如果在牛客网中,我们可以直接通过,但是如果是本地的编译器,则还需要定义其结点,具体结点的实现定义用java实现如下:
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
思路二:
根据前面对中序遍历的介绍,如果一个节点的右子树不为空,那么该节点的下一个节点是右子树的最左节点;那么需要首先判断给定的结点属于哪一种:如果它存在右子树,说明它是子树的父结点,下一个节点在其右子树中。如果右子树存在左孩子结点,那么下一个就是左孩子结点,否则说明它就是叶子结点,直接返回。如果它不存在右子树,说明当前结点为叶子节点:如果当前结点为右叶子,那么下一个就是它的父结点,即它next域指向的结点。如果它的父节点有左叶子,说明下一个节点就是父节点
② 否则,向上找第一个左链接指向的树包含该节点的祖先节点。
接下来我们分别用java和python两种语言来实现该思路:
1、首先我们用java实现该思路:
public class Solution{
public TreeLinkNode GetNext(TreeLinkNode pNode){
if(pNode.right != null){
TreeLinkNode node = pNode.right;
while(node.left != null){
node = node.left;
}
return node;
}else{
while(pNode.next !=null){
TreeLinkNode parent = pNode.next;
if(parent.left == pNode){
return parent;
}
pNode = pNode.next;
}
}
return null;
}
}
代码效果图如图所示:
2、接下来我们用Python将其实现:
class Solution:
def GetNext(self, pNode):
if pNode == None:
return None
if pNode.right:
pNode = pNode.right
while pNode.left:
pNode = pNode.left
return pNode
else:
while pNode.next:
if pNode == pNode.next.left:
return pNode.next
pNode = pNode.next
return None
代码效果图如图所示:
但是在本地编译器中我们还需要定义链表结构才能正常运行,具体用python定义链表结构实现如下:
class TreeLinkNode:
def __init__(self, pNode):
self.val = x
self.left = None
self.right = None
self.next = None
思路三:
无论是何种思路,首先要做的就是要知道二叉树的中序遍历。具体如下:
结合上图,我们可发现分成两大类:
1、有右子树的,那么下个结点就是右子树最左边的点;(eg:D,B,E,A,C,G)
2、没有右子树的,也可以分成两类:(a)是父节点左孩子(eg:N,I,L) ,那么父节点就是下一个节点 ;b)是父节点的右孩子(eg:H,J,K,M)找他的父节点的父节点的父节点…直到当前结点是其父节点的左孩子位置。如果没有eg:M,那么他就是尾节点。)。
具体我们用python将其实现:
class Solution:
def GetNext(self, pNode):
if not pNode:
return pNode
if pNode.right:
left1 = pNode.right
while left1.left:
left1 = left1.left
return left1
p = pNode
while pNode.next:
tmp = pNode.next
if tmp.left == pNode:
return tmp
pNode = tmp
代码效果图如图所示:
总结
本题主要通过二叉树的中序遍历来考察我们对二叉树遍历的应用,我们不仅要掌握二叉树的遍历,更要掌握其在不同的应用。本文给出了三种解题方法,并且这三种方法其实都是以中序遍历为依托的。另外我们还通过java和python将其实现。因此,我们在做题的时候,应该多次尝试各种方法,扩展自己的思维,写出优质的代码。总之,我们要继续加油,争取早日找到工作,Good Luck!!!
参考文献
[1] jiangjiane
[2] Forlogen
[3] DrogoZhang
[4] 白马长枪儒雅将