Java实现二叉树的一些操作

28 篇文章 0 订阅
3 篇文章 0 订阅

之前写过关于C语言实现二叉树的一些操作

这段时间正好在看Java,就将一些常见的二叉树问题转换为Java语言实现

1.二叉树的先序,中序,后序,层序遍历

2.求二叉树的节点个数

3.求二叉树叶子节点个数

4.求二叉树的高度

5.求二叉树第K层元素个数

6.判断二叉树是否为平衡二叉树

7.判断二叉树是否为完全二叉树

8.判断两棵树是否相同

9.求二叉树的镜像树

10.判断两棵树是否为镜像

11.求二叉树的两个节点的最小父节点

1.二叉树的先序、中序、后序、层序遍历(递归与非递归)

先序遍历:

二叉树的先序遍历顺序为:先打印根节点,再遍历左子树,最后遍历右子树

递归思路:

若二叉树为空,则直接返回空

若二叉树非空,先打印根节点,再先序遍历左子树,再先序遍历右子树

import Demo.TreeNode;

//递归实现
//二叉树的先序遍历
public class PreOrderTraversalRec {
    public static void preOrderTraversal(TreeNode root)
    {
        if(root == null)
        {
            return;
        }
        System.out.println(root.val);
        preOrderTraversal(root.left) ;
        preOrderTraversal(root.right);
    }
}

非递归思路:

使用一个stack栈来辅助完成,

先将根节点入栈,再让stack栈进入循环,

此时让stack出栈一个元素并打印

若该元素右孩子存在,将右孩子入栈,再将该元素的左孩子入栈

往复循环

注:一定要先判断右孩子并先让右孩子先入栈,因为栈是先进后出,而先序遍历关于左右子树的顺序是先打印左孩子,再打印右孩子,所以要求先出栈的元素为左孩子,所以先让右孩子入栈

import Demo.TreeNode;

import java.util.Stack;

//非递归实现
//二叉树的先序遍历
public class PreOrderTraversal {
    public static void preOrderTraversal(TreeNode root)
    {
        if(root == null)
        {
            return;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();//使用栈
        stack.add(root);
        while (!stack.isEmpty())
        {
            TreeNode cur = stack.pop();//先将元素出栈
            System.out.println(cur.val);//打印内容
            if(cur.right != null)
            {
                stack.push(cur.right);//先入栈右节点,因为栈是先进后出(
                // 先序遍历是先访问左子树,即先出栈打印左子树,所以后入栈左子树)
            }
            if(cur.left != null)
            {
                stack.push(cur.left);
            }
        }
    }
}

中序遍历:

二叉树的中序遍历顺序为:先遍历左子树,再打印根节点,最后再遍历右子树

递归思路:

若二叉树为空,则直接返回空

若二叉树非空,先中序遍历左子树,再打印根节点,再中序遍历右子树

import Demo.TreeNode;

public class InOrderTraversalRec {
    public static void inOrderTraversal(TreeNode root)
    {
        if(root == null)
        {
            return;
        }
        inOrderTraversal(root.left);
        System.out.println(root.val);
        inOrderTraversal(root.right);
    }
}

非递归思路:

使用一个stack栈来辅助完成,

使用一个新节点cur,开始指向根节点,

此时让stack栈进入循环,将cur入栈,将cur再次指向cur的左孩子,循环地依次将cur入栈,

当入栈结束后,将栈中一个元素进行出栈,该元素记为cur,并打印cur,

再将cur指向cur的右孩子,直到栈为空,循环结束

import Demo.TreeNode;

import java.util.Stack;

//非递归实现
//二叉树的中序遍历
public class InOrderTraversal {
    public static void inOrderTraversal(TreeNode root)
    {
        if(root == null)
        {
            return;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();//使用栈
        TreeNode cur = root;
        while (true)
        {
            while (cur != null)//从根节点开始,将节点的左子树依次入栈
            {
                stack.push(cur);
                cur = cur.left;
            }
            if(stack.isEmpty())
            {
                break;
            }
            cur = stack.pop();//左子树入栈结束,将栈中元素出栈,打印
            System.out.println(cur.val);
            cur = cur.right;//再循环将右子树入栈
        }
    }
}

后序遍历:

二叉树的后序遍历顺序为:先遍历左子树,再遍历右子树,最后再打印根节点

递归思路:

若二叉树为空,则直接返回空

若二叉树非空,先后序遍历左子树,再后序遍历右子树,最后再打印根节点

//递归的实现
//二叉树的后序遍历
public class PostOrderTraversalRec {
    public static void postOrderTraversalRec(TreeNode root)
    {
        if(root == null)
        {
            return;
        }
        postOrderTraversalRec(root.left);
        postOrderTraversalRec(root.right);
        System.out.println(root.val);
    }

}

非递归思路:

使一个stack栈和outputStack栈来辅助完成,

其中stack栈保存cur和他的左右子树,outputStack栈中保存的是stack栈反转过来的栈

先将根节点入栈,进入循环

创建新节点cur为stack出栈的元素,再将出栈的元素cur入栈到outputStack栈中

再将cur的左右孩子入栈到stack栈栈中

直到栈为空,循环结束

循环结束后将outputStack栈中元素依次出栈打印

import Demo.TreeNode;

import java.util.Stack;

//非递归实现
//二叉树的后序遍历
public class PostOrderTraversal {
    public static void postOrderTraversalRec(TreeNode root)
    {
        if(root == null)
        {
            return;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();//stack栈中保存cur和他的左右子树
        Stack<TreeNode> outputStack = new Stack<TreeNode>();//outputStack栈中保存stack栈翻转过来的栈
        stack.push(root);
        while (!stack.isEmpty())//保证将stack栈中内容全部翻转到outputStack栈中
        {
            TreeNode cur = stack.pop();
            outputStack.push(cur);
            if(cur.left != null)
            {
                stack.push(cur.left);
            }
            if(cur.right != null)
            {
                stack.push(cur.right);
            }
        }
        while (!outputStack.isEmpty())
        {
            System.out.println(outputStack.pop().val);//将outputStack栈中内容全部打印
        }
    }
}

层序遍历:

二叉树的层序遍历顺序为:按层遍历

递归思路:

使用一个大的ArrayList,里面包含了每一层的ArrayList

大的ArrayList的大小与里面层数有关

//递归的实现
//二叉树的层序遍历
//用一个大的ArrayList,里面包含了每一层的ArrayList
//大的ArrayList的size和层数depth有关
public class LevelOrderTraversalRec {
    public static void levelOrderTraversal(TreeNode root)
    {

        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        depth(root,0,result);
        System.out.println(result);
    }

    private static void depth(TreeNode root, int depth, ArrayList<ArrayList<Integer>> result) {
        if(root == null)
        {
            return;
        }
        if(depth >= result.size())
        {
            result.add(new ArrayList<Integer>());
        }
        result.get(depth).add(root.val);
        depth(root.left,depth + 1,result);
        depth(root.right,depth + 1,result);
    }
}

非递归思路:

相当于广度优先搜索,使用队列实现,队列初始化,将根节点入队列

开始进入循环,先出队列一个元素,并打印该节点

再将该节点的左右孩子入队列

直到队列为空,循环结束

import Demo.TreeNode;

import java.util.LinkedList;

//非递归的实现
//二叉树的层序遍历
public class LevelOrderTraversal {
    public static void levelOrderTraversal(TreeNode root)
    {
        if(root == null)
        {
            return;
        }
        LinkedList<TreeNode> list = new LinkedList<>();//使用队列(先进先出)
        list.add(root);
        while(!list.isEmpty())
        {
            TreeNode cur = list.pollFirst();//移除队列第一个元素
            System.out.println(cur.val);
            if(cur.left != null)
            {
                list.add(cur.left);
            }
            if(cur.right != null)
            {
                list.add(cur.right);
            }
        }
    }
}

2.求二叉树节点个数

递归思路:

二叉树节点个数 = 左子树节点个数 + 右子树节点个数

import Demo.TreeNode;

//递归的方式实现O(n)
//二叉树中节点个数
//二叉树节点个数 = 左子树节点个数 + 右子树节点个数 + 1
public class GetNodeNumRec {
    public static int getNodeNum(TreeNode root)
    {
        if(root == null)
        {
            return 0;
        }
        return getNodeNum(root.left) + getNodeNum(root.right) + 1;
    }
}

非递归思路:

使用一个队列queue来辅助完成

先将根节点入队,此时记录节点个数为count = 1,然后进入循环

将队列出队列一个元素,(count要 - 1)然后将该元素的左右子树入队列,将count的个数依次++

最终循环结束,返回count

import Demo.TreeNode;

import java.util.LinkedList;
import java.util.Queue;


//非递归方式实现O(n)
//二叉树节点个数
public class GetNodeNum {
    public static int getNodeNum(TreeNode root)
    {
        if(root == null)
        {
            return 0;
        }
        Queue<TreeNode> queue = new LinkedList<>();//创建队列
        queue.add(root);
        int count = 1;//此时节点个数为1(插入了根节点)
        while (!queue.isEmpty())
        {
            TreeNode cur = queue.remove();//将队列中的一个元素从头出队列
            if(cur.left != null)
            {
                queue.add(cur.left);
                count++;
            }
            if(cur.right != null)
            {
                queue.add(cur.right);
                count++;
            }
        }
        return count;
    }
}

3.求二叉树叶子节点个数

递归思路:

二叉树叶子节点个数 = 左子树叶子节点数 + 右子树叶子节点数 


import Demo.TreeNode;

//递归实现
//二叉树叶子节点个数
public class GetLeafNodeNumRec {
    public static int getLeafNodeNum(TreeNode root)
    {
        if(root == null)
        {
            return 0;
        }
        if(root.left == null && root.right == null)
        {
            return 1;
        }
        return getLeafNodeNum(root.left) + getLeafNodeNum(root.right);
    }
}

非递归思路:

使用队列来辅助完成

将根节点入队列,开始进入循环

将一个元素出队列,再分别将左右子节点入队列,

若节点没有左右孩子,则将count(叶子节点个数)+1,

直到队列为空,循环结束,返回count


//非递归实现
//二叉树叶子节点个数
public class GetLeafNodeNum {
    public static int getLeafNodeNum(TreeNode root)
    {
        if(root == null)
        {
            return 0;
        }
        LinkedList<TreeNode> list = new LinkedList<TreeNode>();
        list.add(root);
        int count = 0;
        while (!list.isEmpty())
        {
            TreeNode cur = list.pop();
            if(cur.left != null)
            {
                list.add(cur.left);
            }
            if(cur.right != null)
            {
                list.add(cur.right);
            }
            if(cur.left == null && cur.right == null)
            {
                count++;
            }
        }
        return count;
    }
}

4.求二叉树的高度

递归思路:

二叉树深度 = max (左子树深度,右子树深度) + 1(为根节点所在层数)

//递归实现O(n)
//二叉树深度 = 根节点左右子树深度更大的深度 + 1
public class GetTreeNodeRec {
    public static int getTreeDepth(TreeNode root)
    {
        if(root == null)
        {
            return 0;
        }
        TreeNode leftNode = root.left;
        TreeNode rightNode = root.right;
        return Math.max(getTreeDepth(leftNode),getTreeDepth(rightNode)) + 1;
    }
}


非递归思路:

使用链表来辅助完成,变量curCount表示本层元素个数,变量nextCount表示下一层元素个数,变量depth表示二叉树的高度

先将根节点入队列,将curCount++,进入循环

将队列中一个元素出队列,将curCount--,

将该节点的左右节点压入队列,同时将nextCount++,(因为此时记录的该节点的子节点个数,即下一层节点个数)

curCount为0,表示本层元素全部遍历结束,将depth++,

并要开始进行下一层,要将curCount=nextCount,nextCount=0

当链表为空,循环结束,返回depth

import Demo.TreeNode;

import java.util.LinkedList;

//非递归实现O(n)
//二叉树的深度
public class GetTreeDept {
    public static int getTreeDepth(TreeNode root)
    {
        if(root == null)
        {
            return 0;
        }
        LinkedList<TreeNode> list = new LinkedList<TreeNode>();//创建链表
        list.add(root);
        int curCount = 1;//本层元素个数
        int nextCount = 0;//下一层元素个数
        int depth = 0;//二叉树深度
        while(!list.isEmpty())
        {
            TreeNode cur = list.remove();//先移出一个元素
            curCount--;//此时当前行元素个数-1
            if(cur.left != null)
            {
                list.add(cur.left);
                nextCount++;
            }
            if(cur.right != null)
            {
                list.add(cur.right);
                nextCount++;
            }
            if(curCount == 0)//若当前行元素个数=0,说明本行遍历结束,要开始进行下一行
            {
                depth++;//深度+1
                curCount = nextCount;//当前行元素个数就变为之前下一行元素个数
                nextCount = 0;//下一行元素个数变为0
            }
        }
        return depth;
    }
}

5.求二叉树第K层元素个数

递归思路:

二叉树第K层节点个数 = 左子树的K-1层节点个数 + 右子树K-1层节点个数

注:为什么是K-1行?因为对于左子树在根节点的下一层,根节点的K层就是左右子树的K-1层

import Demo.TreeNode;
//递归实现
//二叉树第K层节点个数
public class GetLevelKNodeNumRec {
    public static int getLevelKNodeNum(TreeNode root,int k)
    {
        if(root == null || k <= 0)
        {
            return 0;
        }
        if(k == 1)
        {
            return 1;
        }
        return getLevelKNodeNum(root.left,k - 1) + getLevelKNodeNum(root.right,k - 1);
    }
}

非递归思路:

类似于求二叉树的深度,

多增加了一个变量i来记录当前层数,将循环结束条件多加了一条:i<K,最后返回的值为curCount

详细见下面代码

//非递归实现
//二叉树第K层节点个数
//类似于求二叉树深度
import Demo.TreeNode;

import java.util.LinkedList;

public class GetLevelKNodeNum {
    public static int getLevelKNodeNum(TreeNode root,int k)
    {
        if(root == null || k <= 0)
        {
            return 0;
        }
        if(k == 1)
        {
            return 1;
        }
        LinkedList<TreeNode> list = new LinkedList<TreeNode>();
        list.add(root);
        int curCount = 1;
        int i = 1;
        int nextCount = 0;
        while(!list.isEmpty() && i < k)
        {
            TreeNode cur = list.pop();
            curCount--;
            if(cur.left != null)
            {
                list.add(cur.left);
                nextCount++;
            }
            if(cur.right != null)
            {
                list.add(cur.right);
                nextCount++;
            }
            if(curCount == 0)
            {
                curCount = nextCount;
                i++;
                nextCount = 0;
            }
        }
        return curCount;
    }
}

6.判断二叉树是否为平衡二叉树

递归思路:

平衡二叉树又称为AVL树:要求左右左子树之差不大于1,这里默认空二叉树是平衡二叉树

是否为平衡二叉树?判断左右子树是否为平衡二叉树,只有左右子树都是平衡二叉树才是平衡二叉树

具体实现见代码

import Demo.TreeNode;

import static Demo.GetTreeDepth.GetTreeNodeRec.getTreeDepth;

//递归实现
//二叉树是否为平衡二叉树
//平衡二叉树AVL:左右子树之差不大于1,默认空树是AVL
public class IsAVL {
    public static boolean isAVL(TreeNode root)
    {
        if(root == null)
        {
            return true;
        }
        if(Math.abs(getTreeDepth(root.left) - getTreeDepth(root.right)) > 1)
        {
            return false;
        }
        boolean leftisAVL = isAVL(root.left);
        boolean rightisAVL = isAVL(root.right);
        return leftisAVL && rightisAVL;
    }
}

7.判断二叉树是否为完全二叉树

非递归思路:

完全二叉树定义:设二叉树的深度为h,除第h层外,其他各层(1~h-1层)的节点数都达到最大,第h层所有节点都连续集中在最左边

使用队列来辅助完成, 创建变量mustHasNoChildNode初始状态为false表示,一定没有子节点

和变量result初始状态为true表示返回结果,让根节点先入队列

进入循环,先将一个元素除列,

若此时变量mustHasNoChildNode的状态为true,则表示当前出队列的节点一定没有左右子树,所以判断当前节点是否存在左右节点,只要有一个,就将变量result赋值为false

若此时变量mustHasNoChildNode的状态为false,则要判断当前节点的情况

若有左右孩子,将元素入队列,继续进入循环

若有左孩子,没有右孩子,则当前mustHasNoChildNode状态变为true,并将左孩子入队列

若有右孩子,没有左孩子,则result状态直接变为false,

若没有左右孩子,则将mustHasNoChildNode状态变为true

import Demo.TreeNode;

import java.util.LinkedList;

//非递归方式实现
//判断二叉树是否为完全二叉树
public class IsCompleteTree {
    public static boolean isCompleteTree(TreeNode root)
    {
        if(root == null)
        {
            return false;
        }
        LinkedList<TreeNode> list = new LinkedList<TreeNode>();
        boolean mustHasNoChildNode = false;
        boolean result = true;
        list.add(root);
        while (!list.isEmpty())
        {
            TreeNode cur = list.pop();
            if(mustHasNoChildNode)
            {
                if(cur.left != null || cur.right != null)
                {
                    result = false;
                    break;
                }
            }
            else
            {
                if(cur.left != null && cur.right != null)
                {
                    //有左右孩子
                    //入队列
                    list.add(cur.left);
                    list.add(cur.right);
                }
                else if (cur.left != null && cur.right == null)
                {
                    //只有左孩子,没有右孩子
                    mustHasNoChildNode = true;
                    list.add(cur.left);
                }
                else if (cur.left == null && cur.right != null)
                {
                    //只有右孩子,没有左孩子
                    //一定不是完全二叉树
                    result = false;
                    break;
                }
                else
                {
                    //没有左右孩子
                    mustHasNoChildNode = true;
                }
            }
        }
        return result;
    }
}

8.判断两棵树是否相同

递归思路:

判断两棵树是否相同?

首先要判断树的结构是否相同?都要同时有左子树,或者右子树

其次再判断节点数据是否相同

//递归实现
//判断两个二叉树是否相同
public class IsSameTreeRec {
    private static boolean isSameTree(TreeNode root1,TreeNode root2)
    {
        if(root1 == null && root2 == null)
        {
            return true;
        }
        if(root1 == null && root2 != null || root1 != null && root2 == null)
        {
            return false;
        }
        if(root1.val != root2.val)
        {
            return false;
        }
        return isSameTree(root1.left,root2.left) && isSameTree(root1.right,root2.right);
    }
}

非递归思路:

首先先要判断结构

然后使用两个链表来辅助完成,将两个树的根节点入队列,进入循环

将两个队列分别出队一个节点,若两个节点相同,

判断,若两个节点的左子树都不为空,将左孩子入队列,再判断右子树,将右孩子入队列

然后继续进入循环,若两个节点不相等,直接返回false

import Demo.TreeNode;

import java.util.LinkedList;

//非递归实现
//判断两个二叉树是否相同
public class IsSameTree {
    private static boolean isSameTree(TreeNode root1, TreeNode root2)
    {
        if(root1 == null && root2 == null)
        {
            return true;
        }
        if(root1 == null && root2 != null || root1 != null && root2 == null)
        {
            return false;
        }
        if(root1.val != root2.val)
        {
            return false;
        }
        LinkedList<TreeNode> list1 = new LinkedList<TreeNode>();
        LinkedList<TreeNode> list2 = new LinkedList<TreeNode>();
        list1.add(root1);
        list2.add(root2);
        while (!(list1.isEmpty() && list2.isEmpty()) )
        {
            TreeNode cur1 = list1.poll();
            TreeNode cur2 = list2.poll();
            if(cur1.val == cur2.val)
            {
                if(cur1.left != null && cur2.left != null)
                {
                    list1.add(cur1.left);
                    list2.add(cur2.left);
                }
                if(cur1.right != null && cur2.right != null)
                {
                    lst1.add(cur1.right);
                    list2.add(cur2.right);
                }
                continue;
            }
            else
            {
                return false;
            }
        }
        return false;
    }

}


9.求二叉树的镜像

破环原来二叉树实现

递归思路:

镜像树就是树1的左子树是树2的右子树,树1的右子树是树2的左子树

递归实现就是将左子树做镜像操作,将右子树做镜像操作,但此时左子树还是左子树,右子树还是右子树,最后要将左子树等于之前交换过的有右子树,右子树等于之前交换过的左子树

//递归的实现
//求二叉树的镜像
//破坏原来的树

import Demo.TreeNode;

public class mirrorRec {
    public static TreeNode mirror(TreeNode root)
    {
        if(root == null)
        {
            return null;
        }
        TreeNode left = mirror(root.left);//此时左子树进行了镜像操作(不是左子树变为了右子树)
        TreeNode right = mirror(root.right);//此时右子树进行了镜像操作(不是右子树变为了左子树)

        root.left = right;
        root.right = left;
        return root;
    }
}

非递归思路:

使用一个栈来辅助完成

先将根节点入栈,进入循环

将栈顶元素出栈,将该节点的左右孩子交换(即交换两个元素),然后将右孩子节点和左孩子节点一次入栈,再次循环

直到栈为null,循环结束

//非递归的实现
//求二叉树的镜像
//破坏原来的树

import Demo.TreeNode;

import java.util.Stack;

public class mirror {
    public static void mirror(TreeNode root)
    {
        if(root == null)
        {
            return ;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(root);
        while (!stack.isEmpty())
        {
            TreeNode cur = stack.pop();
            TreeNode temp = cur.left;
            cur.left = cur.right;
            cur.right = temp;
            if(cur.right != null)
            {
                stack.push(cur.right);
            }
            if(cur.left != null)
            {
                stack.push(cur.left);
            }
        }
    }
}

不破坏原来二叉树实现

递归思路:

与破坏树的结构的区别在于,在开始的时候创建了一棵新树

//递归的实现
//求二叉树的镜像
//不破坏原来的树,创建一颗新树
public class mirrorNewRec {
    public static TreeNode mirror(TreeNode root)
    {
        if(root == null)
        {
            return null;
        }
        TreeNode newNode = new TreeNode(root.val);
        newNode.left = mirror(root.right);
        newNode.right = mirror(root.left);
        return newNode;
    }
}
 

非递归思路:

与破坏树的结构的区别在于,使用了两个栈,一个栈指出不进,另一个栈只进不出,最后循环结束的时候全部出栈,详细见代码

//非递归的实现
//求二叉树的镜像
//不破坏原来的树,创建一颗新树

import Demo.TreeNode;

import java.util.Stack;

public class mirrorNew {
    public static TreeNode mirror(TreeNode root)
    {
        if(root == null)
        {
            return null;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();
        Stack<TreeNode> newStack = new Stack<TreeNode>();
        TreeNode newRoot = new TreeNode(root.val);
        stack.push(root);
        newStack.push(newRoot);
        while (!stack.isEmpty())
        {
            TreeNode cur = stack.pop();
            TreeNode newCur = newStack.pop();
            if(cur.right != null)
            {
                stack.push(cur.right);
                newCur.left = new TreeNode(cur.right.val);
                newStack.add(newCur.left);
            }
            if(cur.left != null)
            {
                stack.push(cur.left);
                newCur.right = new TreeNode(cur.left.val);
                newStack.add(newCur.right);
            }
        }
        return newRoot;
    }
}

10.判断两棵树是否为镜像

递归思路:

类似于判断两棵树是否相同

先判断结构,再递归的判断树1的左子树与树2的右子树是否为镜像,树1的右子树与树2的左子树是否为镜像

最后,只有两次判断都为真才说明两棵树为镜像

import Demo.TreeNode;

public class ismirrorRec {
    public static boolean ismirror(TreeNode root1,TreeNode root2)
    {
        if(root1 == null && root2 == null)
        {
            return true;
        }
        if(root1 == null && root2 != null || root1 != null && root2 == null)
        {
            return false;
        }
        if(root1.val != root2.val)
        {
            return false;
        }
        return ismirror(root1.left,root2.right) && ismirror(root1.right,root2.left);
    }
}

11.求二叉树的两个节点的最小父节点

递归思路:

若两个节点分别位于两棵子树上,则返回根节点,

若两个节点都在左子树上,则递归的进行判断

两个节点都在右子树上,则递归的进行判断

下面这个程序还使用了一个来判断节点是否在树上的函数来辅助完成判断

import Demo.TreeNode;

//递归实现
//二叉树两个节点的最小父节点
public class GetLastCommonParentRec {
    public static TreeNode getLastCommonParent(TreeNode root, TreeNode node1, TreeNode node2)
    {
        if(root == null || node1 == null || node2 == null)
        {
            return null;
        }
        if(nodeInSameTree(root.left,node1))//node1在左子树
        {
            if(nodeInSameTree(root.right,node2))//node2在右子树
            {
                return root;//根节点
            }
            else//node2在左子树
            {
                return getLastCommonParent(root.left,node1,node2);//递归判断
            }
        }
        else //node1在右子树
        {
            if(nodeInSameTree(root.left,node2))//node2在左子树
            {
                return root;//根节点
            }
            else//node2在右子树
            {
                return getLastCommonParent(root.right,node1,node2);//递归判断
            }
        }
    }

    private static boolean nodeInSameTree(TreeNode root, TreeNode node) {
        if(root == null || node == null)
        {
            return false;
        }
        if(root == node)
        {
            return true;
        }
        boolean inSameTree = nodeInSameTree(root.left,node);
        if(!inSameTree)
        {
            inSameTree = nodeInSameTree(root.right,node);
        }
        return inSameTree;
    }
}

精简版递归方法:

import Demo.TreeNode;

//递归实现(递归精简版)
//二叉树两个节点的最小父节点
public class GetLastCommonParentRecX {
    public static TreeNode getLastCommonParent(TreeNode root,TreeNode node1,TreeNode node2)
    {
        if(root == null || node1 == null || node2 == null)
        {
            return null;
        }
        if(root.equals(node1) || root.equals(node2))
        {
            return root;
        }
        TreeNode leftCommon = getLastCommonParent(root.left,node1,node2);
        TreeNode rightCommon = getLastCommonParent(root.right,node1,node2);
        if(leftCommon != null && rightCommon != null)
        {
            return root;
        }
        else if(leftCommon == null)
        {
            return rightCommon;
        }
        return leftCommon;
    }
}

非递归思路:

使用两个链表来辅助完成,详细见程序

import Demo.TreeNode;

import java.util.ArrayList;
import java.util.Iterator;

public class GetLastCommonParent {
    private static TreeNode getLastCommonParent(TreeNode root,TreeNode node1,TreeNode node2)
    {
        if(root == null || node1 == null || node2 == null)
        {
            return  null;
        }
        ArrayList<TreeNode> list1 = new ArrayList<TreeNode>();
        ArrayList<TreeNode> list2 = new ArrayList<TreeNode>();
        boolean result1 = getNodePath(root,node1,list1);
        boolean result2 = getNodePath(root,node2,list2);
        if(!result1 || !result2)
        {
            return null;
        }
        TreeNode last = null;
        Iterator<TreeNode> iterator1 = list1.iterator();
        Iterator<TreeNode> iterator2 = list2.iterator();

        while (iterator1.hasNext() && iterator2.hasNext())
        {
            TreeNode temp1 = iterator1.next();
            TreeNode temp2 = iterator2.next();
            if(temp1 == temp2)
            {
                last = temp1;
            }
            else
            {
                break;
            }
        }
        return last;
    }

    private static boolean getNodePath(TreeNode root, TreeNode node, ArrayList<TreeNode> list) {
        if(root == null)
        {
            return false;
        }
        list.add(root);
        if(root == node)
        {
            return true;
        }
        boolean found = false;
        found = getNodePath(root.left,node,list);
        if(!found)
        {
            found = getNodePath(root.right,node,list);
        }
        if(!found)
        {
            list.remove(root);
        }
        return found;
    }
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值