剑指offer<树篇>
二叉树的下一个节点
题目描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
重点思路:假设这棵树只有3个节点
准确的说:应该是:
有三种情况:
1.如果当前结点有右子树,那么下一个结点就是右子树的最左结点。
2.如果当前结点没有右子树,但是是它父结点的左子结点,那么下一个结点就是他的父结点。
3.如果当前结点既没有右子树,并且还是它父结点的右子结点:
那么沿着指向父结点的指针一直向上遍历,直到找到一个是它父结点的左子结点的结点。
如果这样的结点存在,那么这个结点的父结点就是我们要找的下一个结点。
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode)
{
if(pNode==null) return pNode;
//如果是左节点,并且没有子节点,返回 父节点
//当前为左节点
if(pNode.right==null&&pNode.next!=null&&pNode.next.left==pNode) return pNode.next;
//当前为右节点
if(pNode.right==null) return father(pNode);
//当前是中节点节点,返回遍历右子树的左节点
if(pNode.right!=null) return left(pNode.right);
return null;
}
private TreeLinkNode left(TreeLinkNode root)
{
if(root==null) return root;
if(root.left!=null)
{
root = root.left;
}
return root;
}
/*
是其父节点的左节点
*/
private TreeLinkNode father(TreeLinkNode root)
{
if(root==null) return root;
while(root.next!=null)
{
if(root.next.left==root)
{
break;
}
root = root.next;
}
return root.next;
}
}
第二题:
对称的二叉树
题目描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
boolean isSymmetrical(TreeNode pRoot)
{
if(pRoot==null) return true;
return isEqual(pRoot.left,pRoot.right);
}
boolean isEqual(TreeNode left,TreeNode right)
{
if(left==null&&right==null) return true;
if(left==null||right==null) return false;
if(left.val != right.val) return false;
return isEqual(left.right,right.left)&&isEqual(left.left,right.right);
}
}
第3题:
之字打印二叉树
题目描述
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
import java.util.*;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ArrayList<ArrayList<Integer> > Print(TreeNode root) {
ArrayList<ArrayList<Integer>> ans = new ArrayList();
if(root==null) return ans;
LinkedList<TreeNode> q = new LinkedList();
q.offer(root);
boolean right = true;
while(q.size()>0)
{
ArrayList<Integer> cur = new ArrayList(q.size());
int size = q.size();
Iterator<TreeNode> iter = null;
if(right)
{
iter = q.iterator();
while(iter.hasNext())
{
cur.add(iter.next().val);
}
}else{
iter = q.descendingIterator();
while(iter.hasNext())
{
cur.add(iter.next().val);
}
}
ans.add(cur);
right = !right;
while(--size>=0)
{
TreeNode top = q.poll();
if(top.left!=null) q.offer(top.left);
if(top.right!=null) q.offer(top.right);
}
}
return ans;
}
}
还有一种是用 null作为分隔符的,也是不错,这里直接用 size记录层数即可
不要忘记迭代器的使用,用惯foreach循环,偶尔也要用用迭代器
第4题:同理
层序遍历二叉树
题目描述
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
import java.util.ArrayList;
import java.util.LinkedList;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
ArrayList<ArrayList<Integer> > Print(TreeNode root) {
ArrayList<ArrayList<Integer> > ans = new ArrayList();
if(root==null) return ans;
LinkedList<TreeNode> q = new LinkedList();
q.offer(root);
while(q.size()>0)
{
ArrayList<Integer> cur = new ArrayList();
int size = q.size();
while(--size>=0)
{
TreeNode top = q.poll();
cur.add(top.val);
if(top.left!=null) q.offer(top.left);
if(top.right!=null) q.offer(top.right);
}
ans.add(cur);
}
return ans;
}
}
第5题: LeetCode有一样的题哦
序列化二叉树
题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
import java.lang.StringBuilder;
import java.util.*;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
String Serialize(TreeNode root) {
StringBuffer sb = new StringBuffer();
dfs(sb,root);
return sb.toString();
}
private int curIndex = -1;
TreeNode Deserialize(String str) {
String[] values = str.split(",");
return preOrder(values);
}
public TreeNode preOrder(String[] values)
{
this.curIndex++;
String value = values[curIndex];
if(value.equals("#"))
{
return null;
}
TreeNode head = new TreeNode(Integer.valueOf(value));
head.left = preOrder(values);
head.right = preOrder(values);
return head;
}
public void dfs(StringBuffer sb,TreeNode root)
{
if(root==null)
{
sb.append("#,");
return;
}
sb.append(root.val+",");
dfs(sb,root.left);
dfs(sb,root.right);
}
}
注意 为什么要将 curIndex 设置为成员变量? 因为二叉树的遍历,这个指针是一路向后不回头的,没办法用局部变量