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