版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dawn_after_dark/article/details/83214300
项目地址:https://github.com/SpecialYy/Sword-Means-Offer
问题
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
解析
这道题考察对二叉树和其遍历方式的理解。中序遍历为“左-根-右”的形式进行访问,所以这道题最笨的方法就是获得中序遍历序列,从而轻松即可获得给定节点的下一个节点。
思路一
递归版中序遍历,用一个list存放遍历的结果,最后遍历这个list从而找到指定节点的下一个节点。
//方法一:纯递归中序遍历二叉树
static List<TreeLinkNode> lists = null;
public TreeLinkNode GetNext1(TreeLinkNode pNode) {
TreeLinkNode root = getRootNode(pNode);
inorderTraversal(root);
int index = 0;
for(int i = 0; i < lists.size(); i++) {
if (lists.get(i) == pNode) {
index = i + 1;
break;
}
}
return index < lists.size() ? lists.get(index) : null;
}
public TreeLinkNode getRootNode(TreeLinkNode pNode) {
while(pNode != null) {
if(pNode.next == null) {
return pNode;
}
pNode = pNode.next;
}
return null;
}
public void inorderTraversal(TreeLinkNode node) {
if(node != null) {
inorderTraversal(node.left);
lists.add(node);
inorderTraversal(node.right);
}
}
思路二
考虑递归版的中序遍历对于高深度的树不友好,所以我令写了一版非递归版的中序遍历。
//方法二:变形的中序遍历,可中断
static TreeLinkNode nextNode = null;
static boolean flag = false;
static boolean findFlag = false;
public TreeLinkNode GetNext2(TreeLinkNode pNode) {
TreeLinkNode root = getRootNode(pNode);
nextNode = null;
flag = false;
findFlag = false;
findNextNode2(root, pNode);
return nextNode;
}
/**
* 非递归中序遍历变形
* @param node
* @param pNode
*/
public void findNextNode2(TreeLinkNode node, TreeLinkNode pNode) {
Stack<TreeLinkNode> stack = new Stack<>();
TreeLinkNode p = node;
boolean flag = false;
while(!stack.isEmpty() || p != null) {
while(p != null) {
stack.push(p);
p = p.left;
}
p = stack.pop();
if(flag) {
nextNode = p;
break;
}
if(p == pNode) {
flag = true;
}
p = p.right;
}
}
思路三
思路三的做法则是标准解法,通过观察发现中序遍历中给定节点的下一个节点的规律。
观察上图,2的下一个节点为4,也就是说当指定节点有右孩子,那么在中序遍历里指定节点的下一个节点为右子树最左的节点。
5的下一个节点为3,也就说说当指定节点没有右孩子时且它是父节点的左孩子,那么在中序遍历里指定节点的下一个节点就是父节点。
4的下一个节点为1,也就说说当指定节点没有右孩子时且它不是父节点的左孩子,那么在中序遍历里指定节点的下一个节点就要向上查找,直到找到该指定节点所在的子树的根节点为其父节点的左孩子,那么该祖先即为指定节点的中序遍历中下一个节点。
//方法三-直接利用中序遍历的下一个节点的特点
public TreeLinkNode GetNext3(TreeLinkNode pNode) {
if(pNode == null) {
return null;
}
if(pNode.right != null) {
pNode = pNode.right;
while(pNode.left != null) {
pNode = pNode.left;
}
return pNode;
} else {
while(pNode.next != null) {
if(pNode.next.left == pNode) {
return pNode.next;
}
pNode = pNode.next;
}
}
return null;
}
总结
实在没思路,可以直接从中序遍历入手,后续可以多观察,找规律。