- 剑指 Offer 面试题 58(Java 版):二叉树的下一结点(中序遍历)
题目:给定一棵二叉树和其中的一个结点,如何找出中序遍历顺序的下一个结点?树中的结点除了有两个分别指向左右子结点的指针以外,还有一个指向父节点的指针。
思路:如果一个结点有右子树,那么它的下一个结点就是它的右子树中的左子结点。也就是说右子结点出发一直沿着指向左子结点的指针,我们就能找到它的下一个结点。
接着我们分析一个结点没有右子树的情形。如果结点是它父节点的左子结点,那么它的下一个结点就是它的父结点。
如果一个结点既没有右子树,并且它还是它父结点的右子结点,这种情形就比较复杂。我们可以沿着指向父节点的指针一直向上遍历,直到找到一个是它父结点的左子结点的结点。如果这样的结点存在,那么这个结点的父结点就是我们要找的下一个结点。
show my code
/**
* 查找中序遍历的下一个结点
* @author innovator
*
*/
public class InOrderNextNode {
public static class BinaryTreeNode{
int value;
BinaryTreeNode leftChild;
BinaryTreeNode rightChild;
BinaryTreeNode parentNode;
public BinaryTreeNode(int v){
this.value = v;
}
}
/**
* 查找中序遍历的下一个结点
* @param root
* @return
*/
public static BinaryTreeNode getNext(BinaryTreeNode root){
if(root == null){
return null;
}
BinaryTreeNode next = null;
//有右子树,那么下一个结点就是右子树的最左结点
if(root.rightChild != null){
BinaryTreeNode right = root.rightChild;
//找到最左结点
while(right.leftChild != null){
right = right.leftChild;
}
next = right;
}else if(root.parentNode != null){
//没有右子树,但是父结点不为空
//1.此结点是父结点的左子结点,那么下一个结点就是父结点
//2.此结点是父结点的右叶子结点,那么下个结点就是其父结点作为左子结点的父结点
BinaryTreeNode parent = root.parentNode;
BinaryTreeNode current = root;
while(parent != null && current == parent.rightChild){
//找到其父结点作为左子结点的父结点
current = parent;
//往上查找
parent = parent.parentNode;
}
//找到了
next = parent;
}
return next;
}
/**
* 中序打印
* @param root
*/
public static void printInOrder(BinaryTreeNode root){
if(root == null){
return;
}
printInOrder(root.leftChild);
System.out.print(" "+root.value);
printInOrder(root.rightChild);
}
// 1
// 2 3
// 4 5 6 7
// 8 9 10 11 12 13 14 15
public static void main(String[] args){
BinaryTreeNode n1 = new BinaryTreeNode(1); // 12
BinaryTreeNode n2 = new BinaryTreeNode(2); // 10
BinaryTreeNode n3 = new BinaryTreeNode(3); // 14
BinaryTreeNode n4 = new BinaryTreeNode(4); // 9
BinaryTreeNode n5 = new BinaryTreeNode(5); // 11
BinaryTreeNode n6 = new BinaryTreeNode(6); // 13
BinaryTreeNode n7 = new BinaryTreeNode(7); // 15
BinaryTreeNode n8 = new BinaryTreeNode(8); // 4
BinaryTreeNode n9 = new BinaryTreeNode(9); // 2
BinaryTreeNode n10 = new BinaryTreeNode(10); // 5
BinaryTreeNode n11 = new BinaryTreeNode(11); // 1
BinaryTreeNode n12 = new BinaryTreeNode(12); // 6
BinaryTreeNode n13 = new BinaryTreeNode(13); // 3
BinaryTreeNode n14 = new BinaryTreeNode(14); // 7
BinaryTreeNode n15 = new BinaryTreeNode(15); // null
n1.leftChild = n2;
n1.rightChild = n3;
n2.leftChild = n4;
n2.rightChild = n5;
n2.parentNode = n1;
n3.leftChild = n6;
n3.rightChild = n7;
n3.parentNode = n1;
n4.leftChild = n8;
n4.rightChild = n9;
n4.parentNode = n2;
n5.leftChild = n10;
n5.rightChild = n11;
n5.parentNode = n2;
n6.leftChild = n12;
n6.rightChild = n13;
n6.parentNode = n3;
n7.leftChild = n14;
n7.rightChild = n15;
n7.parentNode = n3;
n8.parentNode = n4;
n9.parentNode = n4;
n10.parentNode = n5;
n11.parentNode = n5;
n12.parentNode = n6;
n13.parentNode = n6;
n14.parentNode = n7;
n15.parentNode = n7;
System.out.println("中序遍历");
printInOrder(n1);
System.out.println("");
BinaryTreeNode next = getNext(n2);
System.out.println("n2下个结点:"+next.value);
BinaryTreeNode next1 = getNext(n8);
System.out.println("n8下个结点:"+next1.value);
BinaryTreeNode next2 = getNext(n9);
System.out.println("n9下个结点:"+next2.value);
BinaryTreeNode next3 = getNext(n15);
if(next3 != null){
System.out.println("n15下个结点:"+next3.value);
}else{
System.out.println("n15下个结点:null");
}
}
}
- 剑指 Offer 面试题 59(Java 版):对称的二叉树
题目:请实现一个函数来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
思路:通常我们有三种不同的二叉树遍历算法,即前序遍历、中序遍历和后序遍历。在这三种遍历算法中,都是先遍历左子结点再遍历右子结点。我们是否可以定义一种遍历算法,先遍历右子结点再遍历左子结点?比如我们针对前序遍历定义一种对称的遍历算法,即先遍历父节点,再遍历它的右子结点,最后遍历它的左子结点。
我们发现可以用过比较二叉树的前序遍历序列和对称前序遍历序列来判断二叉树是不是对称的。如果两个序列一样,那么二叉树就是对称的。
show my code
/**
* 验证二叉树是否为对称二叉树
* @author innovator
*
*/
public class SymmetricalTree {
public static boolean isSymmetrical(BinaryTreeNode root){
return isSymmetrical(root, root);
}
/**
* 判断是否对称
* @param left
* @param right
* @return
*/
public static boolean isSymmetrical(BinaryTreeNode left,BinaryTreeNode right){
if(left == null && right == null){
return true;
}
if(left == null || right == null){
return false;
}
if(left.value != right.value){
return false;
}
//此结点值相同,再比较他们的左右子树的值
//前序遍历的结果和对称前序遍历结果对比
return isSymmetrical(left.leftNode, right.rightNode)
&& isSymmetrical(left.rightNode, right.leftNode);
}
private static void assemble(BinaryTreeNode node,BinaryTreeNode
left,BinaryTreeNode right) {
node.leftNode = left;
node.rightNode = right;
}
// 1
// 2 2
// 4 6 6 4
// 8 9 10 11 11 10 9 8
public static void main(String[] args) {
BinaryTreeNode n1 = new BinaryTreeNode(1);
BinaryTreeNode n2 = new BinaryTreeNode(2);
BinaryTreeNode n3 = new BinaryTreeNode(2);
BinaryTreeNode n4 = new BinaryTreeNode(4);
BinaryTreeNode n5 = new BinaryTreeNode(6);
BinaryTreeNode n6 = new BinaryTreeNode(6);
BinaryTreeNode n7 = new BinaryTreeNode(4);
BinaryTreeNode n8 = new BinaryTreeNode(8);
BinaryTreeNode n9 = new BinaryTreeNode(9);
BinaryTreeNode n10 = new BinaryTreeNode(10);
BinaryTreeNode n11 = new BinaryTreeNode(11);
BinaryTreeNode n12 = new BinaryTreeNode(11);
BinaryTreeNode n13 = new BinaryTreeNode(10);
BinaryTreeNode n14 = new BinaryTreeNode(9);
BinaryTreeNode n15 = new BinaryTreeNode(8);
assemble(n1, n2, n3);
assemble(n2, n4, n5);
assemble(n3, n6, n7);
assemble(n4, n8, n9);
assemble(n5, n10, n11);
assemble(n6, n12, n13);
assemble(n7, n14, n15);
assemble(n8, null, null);
assemble(n9, null, null);
assemble(n10, null, null);
assemble(n11, null, null);
assemble(n12, null, null);
assemble(n13, null, null);
assemble(n14, null, null);
assemble(n15, null, null);
System.out.println(isSymmetrical(n1));
}
}
结果:true