1、二叉树的基本操作
构建二叉树的类
public class BinaryTree{
static class TreeNode {
public char val;
public TreeNode left;
public TreeNode right;
public TreeNode(char val) {
this.val = val;
}
}
public TreeNode createTree() {
TreeNode A = new TreeNode('A');
TreeNode B = new TreeNode('B');
TreeNode C = new TreeNode('C');
TreeNode D = new TreeNode('D');
TreeNode E = new TreeNode('E');
TreeNode F = new TreeNode('F');
TreeNode G = new TreeNode('G');
TreeNode H = new TreeNode('H');
A.left = B;
A.right = C;
B.left = D;
B.right = E;
C.left = F;
C.right = G;
E.right = H;
return A;
}
}
1.1获取树中结点的个数
思路:获取树中结点个数 = 获取树中左子树结点个数 + 右子树结点个数。递归返回的标志在于,遇到了一个结点,它没有左右子树,则返回。
public int size(TreeNode root){
if(root == null){
return 0;
}
return size(root.left) + size(root.right) + 1;
}
1.2获取叶子结点的个数
思路:获取树中叶子结点个数 = 获取树中左子树叶子结点个数 + 右子树叶子结点个数。遇到叶子则返回1,否则就一直递归左右子树。
int getLeafNodeCount(TreeNode root) {
//左右都为空,即为叶子
if (root == null) {
return 0;
}
if (root.left == null && root.right == null) {
return 1;
}
return getLeafNodeCount(root.left) + getLeafNodeCount(root.right);
}
1.3获取第k层结点的个数
思路:从root开始递归,每递归一次,k-=1,递归终止条件是k==1。递归的内容是求k层结点,可以转化为求k-1层结点的个数。
int getk(TreeNode root,int k){
if (root==null){
return 0;
}
if (k==1){
return 1;
}
return getk(root.left,k-1) + getk(root.right,k-1)
}
1.4获取二叉树的高度
思路:整棵树的高度 = max(左子树高度 , 右子树高度) + 1。递归终止条件为左树和右树都为null,就返回,此时是max(0 + 0) + 1即返回1。
int getHeight(TreeNode root) {
if (root == null) {
return 0;
}
return Math.max(getHeight(root.left), getHeight(root.right)) + 1;
}
1.5检测值为value的元素是否存在
思路:遍历,判断是否相等。如果当前根不是,就在左子树找,左子树找完了没有,就在右子树找。如果都没有就表示值不存在。
TreeNode find(TreeNode root, char val) {
if (root == null) {
return null;
}
if (root.val == val) {
return root;
}
TreeNode ret1 = find(root.left, val);
if (ret1 != null) {
return ret1; //找到了,不去右边了
}
TreeNode ret2 = find(root.right, val);
if (ret2 != null) {
return ret2;
}
return null;
}
1.6层序遍历二叉树
思路:从上到下,从左到右,一次遍历。拿一个队列来接收,先进先出,按照根左右的顺序存入,并输出
void levelOrder(TreeNode root) {
if(root == null){
return ;
}
//先放先出,根左右放入,根左右打印
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
//打印输出queue里的值
TreeNode cur = queue.poll();
System.out.print(cur.val + " ");
//存入左
if (cur.left != null){
queue.offer(cur.left);
}
//存入右
if (cur.right != null){
queue.offer(cur.right);
}
}
}
1.7判断一个二叉树是不是完全二叉树
思路:通过判断队列中有无非空元素
// 判断一棵树是不是完全二叉树
boolean isCompleteTree(TreeNode root) {
if (root == null) {
return true;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode cur = queue.poll();
if (cur != null) {
//存入左右元素
queue.offer(cur.left);
queue.offer(cur.right);
} else {
break;//如果cur为空,就结束循环
}
}
//判断队列当中是否有非空元素,有则不是完全,没有则是完全
while (!queue.isEmpty()) {
//一个元素一个元素的出队,来判断有没有非空元素
TreeNode tmp = queue.peek();
//有空直接出
if (tmp == null){
queue.poll();
}else{
//有元素直接返回false,不是完全二叉树
return false;
}
}
//如果队列走完了,说明全是空,则必是完全二叉树
return true;
}
2、二叉树的OJ题
2.1检查两颗树是否相同。
思路:1.确定结构上相同;2.确定结点值上相同。要判断两棵树是否相同,需判断根是否相同,左子树是否相同,右子树是否相同
public boolean isSameTree(TreeNode p, TreeNode q) {
//给根做文章,判断根
//一个为空
if (p == null && q != null || p != null && q == null) {
return false;
}
//两个都为空
if (p == null && q == null) {
return true;
}
//两个都不为空,比值
if (p.val != q.val){
return false;
}
//走到这,两个根结点是一样的了,就要递归判断两颗树的左右子树是否相同
return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}
2.2另一颗树的子树。
思路:和根结点比较,如果不相同,那么再和根结点的左右子树相比,如果全部都不相同则返回false
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if (root == null || subRoot == null){
return false;
}
if (isSameTree(root,subRoot)){
return true;
}
if (isSubtree(root.left,subRoot)){
return true;
}
if (isSubtree(root.right,subRoot)){
return true;
}
return false;
}
2.3翻转二叉树。
思路:交换左右结点
public TreeNode invertTree(TreeNode root) {
if (root==null){
return null;
}
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
invertTree(root.left);
invertTree(root.right);
return root;
}
2.4判断一颗二叉树是否是平衡二叉树。
思路:要判断每一个结点的左右子树高度。左树右树高度差<=1。
public boolean isBalanced(TreeNode root) {
//最坏情况下,每个结点都要求高度
//时间复杂度O(N)
if (root == null) {
return true;
}
int left = getHeight(root.left);
int right = getHeight(root.right);
return Math.abs(left - right) <= 1 && isBalanced(root.left) &&
isBalanced(root.right);
}
public boolean isBalanced2(TreeNode root) {
//缩短时间复杂度
//一边求高度,一边判断平衡问题,如果已经不平衡了,则直接返回负数,节省时间
//如果返回的值是正的,就平衡,返回的值是负数,就表示不平衡
return maxDepth(root) >= 0;
}
public int maxDepth(TreeNode root){
if (root==null){
return 0;
}
int leftHeight = maxDepth(root.left);
int rightHeight = maxDepth(root.right);
//满足平衡的情况
if (leftHeight >= 0 && rightHeight >= 0 && Math.abs(leftHeight-rightHeight)<=1){
//在这种情况下,才会返回真实的高度
return Math.max(leftHeight,rightHeight) + 1;
}else {
//不满足平衡,就直接返回-1
return -1;
}
}
2.5对称二叉树。
思路:判断root的左树和root的右树是否对称。
public boolean isSymmetric(TreeNode root) {
if (root == null) {
return false;
}
return isSymmetricChild(root.left, root.right);
}
private boolean isSymmetricChild(TreeNode leftTree, TreeNode rightTree) {
//一空一不空
if (leftTree == null && rightTree != null || leftTree != null && rightTree == null) {
return false;
}
//两个空树
if (leftTree == null && rightTree == null) {
return true;
}
//左右子树的值不相同
if (leftTree.val != rightTree.val){
return false;
}
//如果上述都满足,那么就继续判断下一个左右子节点是否相同
return isSymmetricChild(leftTree.left,rightTree.right) && isSymmetricChild(leftTree.right,rightTree.left);
}
2.6二叉树的构建及遍历。
思路:遍历这个字符串,根据前序遍历的方式创建二叉树,最后通过中序遍历输出结果
import java.util.Scanner;
class treeNode{
public char val;
public treeNode left;
public treeNode right;
public treeNode(char val){
this.val = val;
}
}
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static int i;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextLine()) { // 注意 while 处理多个 case
String str = in.nextLine();
treeNode root = createNode(str);
inOrder(root);
}
}
public static treeNode createNode(String str){
//.1遍历字符串str
treeNode root = null;
if (str.charAt(i) != '#'){
//2.根据前序遍历创建二叉树
root = new treeNode(str.charAt(i));
i++;
root.left = createNode(str);
root.right = createNode(str);
}else{
i++;
}
//3.最后返回根结点
return root;
}
public static void inOrder(treeNode root){
if (root == null){
return ;
}
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
}
2.7二叉树的分层遍历 。
public List<List<Character>> levelOrder2(TreeNode root) {
List<List<Character>> ret = new ArrayList<>();
if(root == null){
return ret;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
//得到当前队列有多大
//通过记录每次当前队列的size数,来统计每一层的list有多少个元素,从queue中出同样的多数量的元素到list中即可
int size = queue.size();
List<Character> tmp = new ArrayList<>();
while (size != 0) {
//打印输出queue里的值
TreeNode cur = queue.poll();
tmp.add(cur.val);
size--;
if (cur.left != null) {
queue.offer(cur.left);
}
if (cur.right != null) {
queue.offer(cur.right);
}
}
ret.add(tmp);
}
return ret;
}