首先要明白树的定义:除了根节点以外,每个节点都只有一个父节点,根节点没有父节点;除了叶子结点以外,每个节点都有一个至多个子节点,叶子结点没有子节点。父节点与子节点之间通过指针链接。
二叉树:树的一种特殊结构,二叉树中每个节点最多只能有两个子节点。
树的基本操作为遍历,按访问根节点的顺序分为前序遍历(根、左、右),中序遍历(左、根、右),后序遍历(左、右、根),分别有递归和非递归六个版本。很多题目就是三种遍历的递归和非递归版本,及三种遍历形成序列性质的延伸。
基于树的递归版本的遍历的考查题目如下:
二叉树的深度(《剑指offer》39题),树的子结构(《剑指offer》18),二叉树中和为某一值的路径(《剑指offer》24)
二叉树的深度:
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
import java.util.*;
public class Solution {
public int TreeDepth(TreeNode root) {
if (root == null) {
return 0;
}
//分治的思想
int left = TreeDepth(root.left);//左子树的深度
int right = TreeDepth(root.right);//右子树的深度
return Math.max(left, right) + 1;
}
}
树的子结构
题目描述:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)。
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
boolean result = false;
if (root1 != null && root2 != null) {
result = helperSubTree(root1, root2);//root2是不是root1的子结构
if (!result) {
//root2是不是root1左子树的子结构
result = helperSubTree(root1.left, root2);
}
if (!result) {
//root2是不是root1右子树的子结构
result = helperSubTree(root1.right, root2);
}
}
return result;
}
//两个树是否相等
public boolean helperSubTree(TreeNode node1, TreeNode node2) {
if (node2 == null) {
return true;
}
if (node1 == null) {
return false;
}
if (node1.val != node2.val) {
return false;
}
return helperSubTree(node1.left, node2.left) && helperSubTree(node1.right, node2.right);
}
}
二叉树中和为某一值的路径
题目描述:输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
import java.util.ArrayList;
public class Solution {
ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> list = new ArrayList<Integer>();
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
if (root == null) {
return res;
}
//加入根节点的值
list.add(root.val);
target -= root.val;
if (target == 0 && root.left == null && root.right == null) {
//新建一个list,后面要继续在原list上面进行操作
res.add(new ArrayList<Integer>(list));
}
FindPath(root.left, target);
FindPath(root.right, target);
//移除当前添加的值
list.remove(list.size() - 1);
return res;
}
}
非递归版本的常见题目待续。
利用前序,中序,后序遍历的性质解题。例如:重建二叉树(《剑指offer》6),二叉树的后序遍历(《剑指offer》24)。
重建二叉树:
题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
TreeNode res = reConstructBT(pre, 0, pre.length - 1, in, 0, in.length - 1);
return res;
}
public TreeNode reConstructBT(int[] pre, int start1, int end1, int[] in, int start2, int end2) {
if (start1 > end1 || start2 > end2) {
return null;
}
//在前序序列中找到根节点
TreeNode node = new TreeNode(pre[start1]);
int flag = pre[start1];
for (int i = start2; i <= end2; i++) {
//找到中序序列中的根节点
if (in[i] == flag) {
//[start + 1, i-start2]为前序遍历的左子树序列, [start2, i - 1]为中序遍历中左子树序列
node.left = reConstructBT(pre, start1 + 1, start1 + i - start2, in, start2, i - 1);
//[start2 + i - start2 + 1, end1]为前序遍历中的右子树序列,[i+1, end2]为中序遍历中的右子树序列
node.right = reConstructBT(pre, start1 + i - start2 + 1, end1, in, i + 1, end2);
break;
}
}
return node;
}
}
二叉树的后序遍历:
题目描述:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
public class Solution {
public boolean VerifySquenceOfBST(int [] sequence) {
if (sequence == null || sequence.length == 0) {
return false;
}
return judgeBST(sequence, 0, sequence.length - 1);
}
public boolean judgeBST(int [] array, int start, int end) {
if (start >= end) {
return true;
}
//序列的最后一个数为二叉树的根节点
int flag = end;
//右子树上的节点均比根节点大
while (flag > start && array[flag - 1] > array[end]) {
flag--;
}
//左子树上的节点均比根节点小
for (int i = flag - 1; i >= start; i--) {
if (array[i] > array[end]) {
return false;
}
}
//判断左,右子树是不是二叉树?
return judgeBST(array, start, flag - 1) && judgeBST(array, flag, end - 1);
}
}