22.1.10 二叉树

22.1.10 二叉树

1. 递归序遍历(系统自动压栈)

(1)先序遍历:(根左右)
  • code:

public static void preOrder(TreeNode tree) {
   if (tree == null)
       return;
   System.out.printf(tree.val + "");
   preOrder(tree.left);
   preOrder(tree.right);
}

 

(2)中序遍历:(左根右)
  • code:

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

 

(3)后序遍历:(左右根)
  • code:

public List<Integer> postorderTraversal(TreeNode root) {
       List<Integer> res = new ArrayList<>();
       //res用来存放后序遍历的结果,遍历res输出后序遍历的结果。
       postOrder(root,res);
       return res;
  }

  public void postOrder(TreeNode node,List<Integer> res){
       if(node == null){
           return;
      }
       postOrder(node.left,res);
       postOrder(node.right,res);
       res.add(node.val);
  }

 

2.非递归序遍历(手写栈)

(1)先序遍历:(压栈顺序:根右左)
  • code:

    public void preOrder(TreeNode tree) {
       Stack<TreeNode> stack = new Stack<>();
       stack.push(tree);//根节点进栈
       while (!stack.empty()) {
           TreeNode t1 = stack.pop();//出栈
           System.out.println(t1.val);
           if (t1.right != null) {
               stack.push(t1.right);//右节点进栈
          }
           if (t1.left != null) {
               stack.push(t1.left);//左节点进栈
          }
      }
  }

 

(2)中序遍历:(压栈顺序:根左右)
  • code:

    public void inOrderTraversal(TreeNode tree) {
       Stack<TreeNode> stack = new Stack<>();
       while (tree != null || !stack.isEmpty()) {
           while (tree != null) {
               stack.push(tree);
               tree = tree.left;
          }
           if (!stack.isEmpty()) {
               tree = stack.pop();
               System.out.println(tree.val);
               tree = tree.right;
          }
      }
  }

 

(3)后序遍历:(先序遍历的逆序)
  • code:

      public static List<Integer> postorderTraversal(Node root) {
       List<Integer> res = new ArrayList<>();
       Stack<Node> stack = new Stack<>();
       if(root == null) return res;
       stack.push(root);
       while(!stack.isEmpty()){
           Node cur = stack.pop();
           res.add(cur.val);
           if(cur.l!=null) stack.push(cur.l);
           if(cur.r!=null) stack.push(cur.r);
      }
       Collections.reverse(res);
       return res;
  }

 

 

3.二叉树的相关概念及其实现判断

(1)如何判断一颗二叉树是否是搜索二叉树(一棵树中所有节点的左孩子都比他小,右孩子都比他大)?
  • 中序遍历,如果最后的结果一直是升序,则该树为搜索二叉树,可以动一个list存储所有的遍历的节点的value,然后遍历list,看list是否一直升序,或者用下面的动态遍历的方法。

  • code:

public static int preValue = Integer.MIN_WALUE;

public static boolean isBST(Node head)
{
   if(head == null)
       return true;
   
   boolean isLeftBst = isBST(head.left);
   if(!isLeftBst)
       return false;
   if(head.value <= preValue)
       return false;
   else
       preValue = head.value;
   return isBST(head.right);//此时左树已经是搜索二差树,整棵树是不是搜索二叉树取决于右数
}

 

(2)如何判断一颗二叉树是完全二叉树?
  • 宽度优先遍历;

  • 任一节点,有右孩子没有左孩子直接返回false;

  • 在满足第一个的条件下,如果遇到了第一个左右孩子不全的节点,在这个节点之后的所有节点必须为叶节点;

public static boolean isCBT(Node head)
{
   if(head == null)
       return true;
   LinkedList<Node> queue = new LinkList<>();
   boolean flag = false;//记录是否遇到过左右孩子不双全的节点。
   Node l = null;
   Node r = null;
   queue.add(head);
   while(!queue.isEmpty())
  {
       head = queue.poll();
       l = head.left;
       r = head.right;
       if((flag && (l != null || r =null )) || (l == null && r!= null))
           return false;
       
       if (l != null)
           queue.add(1);
       
       if(r != null)
           queue.add(r);
       
       if(l == null || r == null)
           flag = true;
  }
   return true;
}

 

(3)如何判断一颗二叉树是否是满二叉树?
  • 可以先定义一个函数用来统计二叉树的最大深度l,在写一个函数统计节点数n,如果满足n=2^l-1,则该树为满二叉树。

(4)如何判断一颗二叉树是否是平衡二叉树(任何一棵子树的左树和右数的高度差不超过一) ?

  • 判断条件:左树平衡,右树平衡,左树与右树的高度差不超过一。

(4)二叉树题目套路:
  • 当一个二叉树题目可以总结为通过向左树要信息和向右树要信息来解决问题时,我们可以用二叉树套路解题。

  • 二叉树套路步骤(例如平衡二叉树):

1)假设以X节点为头,假设可以向X左树和X右树要任何信息 2)在上一步的假设下,讨论以X为头节点的树,得到答案的可能性,确定得到答案的条件(最重要) 3)列出所有可能性后,确定到底需要向左树和右树要什么样的信息 4)把左树信息和右树信息求全集,就是任何一棵子树都需要返回的信息S 5)递归函数都返回定义的信息类,每一棵子树都这么要求 6)写代码,在代码中考虑如何把左树的信息和右树信息整合出整棵树的信息

  • 例如 判断一棵树是不是平衡二叉树:

public static void CreatTree(Node head)
{
Node temp2 = new Node();
temp2.val = 2;
Node temp3 = new Node();
temp3.val = 3;
Node temp4 = new Node();
temp4.val = 4;
Node temp5 = new Node();
temp5.val = 5;
Node temp6 = new Node();
temp6.val = 6;

head.l = temp2;
head.r = temp3;
temp2.l = temp4;
temp2.r = temp5;
temp3.r = temp6;
temp4.l = temp6.l = temp5.l = temp3.l = null;
temp4.r = temp6.r = temp5.r = null;
}

public static class ReturnType //返回值类型,也是我们要从左树和右树上得到的信息。
{
 boolean isBalanced;
 int h;
 
public ReturnType(boolean is, int h)
{
 this.isBalanced = is;
 this.h = h;
}
}
 
public static ReturnType process(Node head)
{
 if(head == null)//要注意基本情况
 return new ReturnType(true,0);
   
    //递归
 ReturnType rType = process(head.r);
 ReturnType lType = process(head.l);
 
    //统计子树的高度
 int height = Math.max(rType.h, lType.h) + 1;

    //判断二叉平衡树的三个条件
 boolean isB = (rType.isBalanced) && (lType.isBalanced) && (Math.abs(rType.h-lType.h))<2;
 
 return new ReturnType(isB,height);
}


public static void main(String[] args)
{
Node head = new Node();
head.val = 1;
CreatTree(head);
if(process(head).isBalanced)
System.out.println("yes") ;
else
System.out.println("no") ;
  }
(5)给定两个二叉树的节点node1和node2,找到他们的最低公共祖先节点
  • node1和node2 只有两种存在情况,其一是其中一个节点在以另外一个节点为根节点的子树上,其二是两个节点在不同的子树上,但两个节点都在以head为根节点的子树上。

  • code:

      public static Node lowestAncestor(Node head,Node n1,Node n2)
{
 if(head == null || head == n1 || head == n2)
 return head;
 
 Node left = lowestAncestor(head.l,n1,n2);
 Node right = lowestAncestor(head.r,n1,n2);
 
 if(left !=null && right !=null)
 return head;
 
 return left!=null?left:right;
}
(6 ) 微软面试折纸问题
  • 问题描述:请把一段纸条竖着放在桌子上,然后从纸条的下边向上方对折1次,压出折痕后 展开。 此时折痕是凹下去的,即折痕突起的方向指向纸条的背面。 如果从纸条的下边向上方连续对折2次,压出折痕后展开,此时有三条折痕,从 上到下依次是下折痕、下折痕和上折痕。 给定一个输入参数N,代表纸条都从下边向上方连续对折N次。 请从上到下打印所有折痕的方向。 例如:N=1时,打印: down N=2时,打印: down down up

  • 分析:根据折纸问题的规律,我们可以发现输出结果其实是一个满二叉树的中序遍历结果。这棵树是以down为根节点,每个节点的左孩子都为down,右孩子都为up的满二叉树。

  • code:

public static void MSPaper(int i,int n,boolean down)
//i表示当前函数来到的层数(第几次折叠),n表示总层数(一共折叠多少次),down == true表示为凹折痕
  {
   //如果当前层数大于总层数,直接返回
       if(i>n)
           return ;
   //以下为中序遍历的代码。
       MSPaper(i+1,n,true);
       System.out.println(down?"凹 ":"凸 ") ;
       MSPaper(i+1,n,false);
  }

public static void main(String[] args)
{
MSPaper(1,3,true);
}
}

 

posted @ 2022-01-12 18:22  张满月。  阅读(30)  评论(0编辑  收藏  举报