欢迎关注个人主页:逸狼
创造不易,可以点点赞吗~
如有错误,欢迎指出~
判断对称二叉树
对称的情况:左右子树都不为空 且 值相等
不对称的情况:
- 左树不为空,右树为空,反之也是
- 左右子树都不为空,但值不一样
public boolean isSymmetric(TreeNode root) {
if(root==null){
return true;
}
return isSymmetricChild(root.left,root.right);
}
public 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);
}
二叉树遍历
知道前序遍历和空树的位置可确定树的结构
#代表空树
首先要先构造树的节点TreeNode
通过遍历字符串(前序遍历), 创建二叉树createTree,
最后用中序遍历来输出二叉树.
注意:遍历字符串的i要定义成 成员变量
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=0;//i要定义成成员变量
public static TreeNode createTree(String str){
TreeNode root=null;
if(str.charAt(i)!='#'){
root=new TreeNode(str.charAt(i));
i++;
root.left=createTree(str);
root.right=createTree(str);
}else{
i++;
}
return root;
}
public static void inorder(TreeNode root){
if(root==null){
return;
}
inorder(root.left);
System.out.print(root.val+" ");
inorder(root.right);
}
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=createTree(str);
inorder(root);
}
}
}
二叉树的层序遍历
使用队列实现
- 首先将 根节点root 放入队列里
- 定义一个cur节点来 遍历二叉树,
- 每次cur出队列时,打印cur的值,
- 再 遍历cur的左子树以及右子树 ,
- 当队列中元素为空后,循环结束
public void levelOrder(TreeNode root){
Queue<TreeNode> queue=new LinkedList<>();
if(root==null){
return ;
}
queue.offer(root);
while(!queue.isEmpty()){
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);
}
}
System.out.println();
}
0j题:层序遍历
这里是创建一个二维数组ret,让每一层为一个元素(ret的一个元素,用list一维数组表示),在每一层里面存放着该层的全部节点,
这里就需要知道每一层的节点个数,下面代码用size表示,
下面代码是在上一题的基础上进行了优化(也可以算是另一种解法)
只有每一层节点都出了队列,才可以开始下一层节点进入队列.
public List<List<Integer>> levelOrder(TreeNode root) {
//创建二位数组,每一个元素代表每一层
List<List<Integer>> ret=new ArrayList<>();
//若是空树,直接返回ret,使数组为空
if(root==null){
return ret;
}
//创建一个队列,并放入根节点
Queue<TreeNode> queue=new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
//用size记录每一层节点的个数
int size=queue.size();
//创建一个一维数组,用于存放每一层的节点的值
List<Integer> list=new ArrayList<>();
while(size>0){
//用cur记录从队列弹出的节点,并放入list数组中
TreeNode cur=queue.poll();
list.add(cur.val);//这里会报错是因为题目里的int,而节点值的类型是char
if(cur.left!=null){
queue.offer(cur.left);
}
if(cur.right!=null){
queue.offer(cur.right);
}
size--;
}
//将list数组存放到ret二维数组中
ret.add(list);
}
return ret;
}
树的左视图:每一层第一个节点
完全二叉树的判断
利用层序遍历思想,当队列弹出的是null,但队列里还有元素时候,就不是完全二叉树.
public 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){
break;
}
queue.offer(cur.left);
queue.offer(cur.right);
}
while (!queue.isEmpty()) {
TreeNode node =queue.peek();
if(node==null){
return false;
}else{
queue.poll();
}
}
return true;
}
}
最近公共祖先判断
//寻找公共祖先
public TreeNode lowestCommonAncestor
(TreeNode root, TreeNode p, TreeNode q) {
if(root==null){
return null;
}
//p或者q==root
if(p==root||q==root){
return root;
}
TreeNode leftTree=lowestCommonAncestor(root.left,p,q);
TreeNode rightTree=lowestCommonAncestor(root.right,p,q);
//两边都不为空
if(leftTree!=null&&rightTree!=null){
return root;
//左边为空
}else if(leftTree!=null){
return leftTree;
//右边为空
}else{
return rightTree;
}
}
法二
类似于求两个链表的交点.
- 获取root到指定节点 路径上的所有节点 放到栈中
- 谁长谁出栈,直到两者一样长
- 两者都分别出栈,直到元素相同,即公共祖先,否则就没有.
getPace是把root到指定节点node 路径下的所有节点 都存储在栈中
//法二
public TreeNode lowestCommonAncestor
(TreeNode root,TreeNode p,TreeNode q){
if(root==null){
return root;
}
Stack<TreeNode> stackP=new Stack<>();
getPath(root,p,stackP);
Stack<TreeNode> stackQ=new Stack<>();
getPath(root,q,stackQ);
//上面代码执行完成,对应的栈存储了指定路径的节点
int sizeP=stackP.size();
int sizeQ=stackQ.size();
if(sizeP>sizeQ){//栈P和Q谁的 元素多谁弹出,直到两者长度相等
int size=sizeP-sizeQ;
while(size!=0){
stackP.pop();
size--;
}
}else{
int size=sizeQ-sizeP;
while(size!=0){
stackQ.pop();
size--;
}
}
while(!stackP.isEmpty() && !stackQ.isEmpty()){
if(stackP.peek()==stackQ.peek()){
return stackP.peek();
}else{
stackP.pop();
stackQ.pop();
}
}
return null;
}
public boolean getPath(TreeNode root, TreeNode node ,Stack<TreeNode> stack){
if(root==null){
return false;
}
stack.push(root);
if(root==node){
return true;
}
boolean flg=getPath(root.left,node,stack);
if(flg){
return true;
}
boolean flg2=getPath(root.right,node,stack);
if(flg2){
return true;
}
stack.pop();
return false;
}
二叉树前序遍历(非递归)
利用栈实现
public void preOrderNot(TreeNode root){
Stack<TreeNode> stack=new Stack<>();
TreeNode cur=root;
while(cur!=null||!stack.isEmpty()){
while(cur!=null){
stack.push(cur);
System.out.print(cur.val+" ");
cur=cur.left;
}
TreeNode top=stack.pop();
cur=top.right;
}
}
二叉树中序遍历(非递归)
public void inOrderNot(TreeNode root){
Stack<TreeNode> stack=new Stack<>();
TreeNode cur=root;
while(cur!=null||!stack.isEmpty()){
while(cur!=null){
stack.push(cur);
cur=cur.left;
}
TreeNode top=stack.pop();
System.out.print(top.val+" ");
cur=top.right;
}
}
二叉树后序遍历(非递归)
public void postOrderNot(TreeNode root){
Stack<TreeNode> stack=new Stack<>();
TreeNode cur=root;
TreeNode prev=null;
while(cur!=null||!stack.isEmpty()){
while(cur!=null){
stack.push(cur);
cur=cur.left;
}
TreeNode top=stack.peek();
if(top.right==null||top.right==prev){
stack.pop();
System.out.print(top.val+" ");
prev=top;//记录当前打印的是谁
}else{
cur=top.right;
}
}
}