满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
完全二叉树:完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。
二叉搜索树:也叫作二叉排序树
前面介绍的树,都没有数值的,而二叉搜索树是有数值的了,二叉搜索树是一个有序树。
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉排序数
二叉平衡树(AVL):它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
二叉树数据结构:
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
二叉树的层序遍历
利用广度优先遍历(BFS):需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,DFS而是用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。
记着判断根节点是不是null!!!
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res=new LinkedList<>();
Queue<TreeNode> queue=new LinkedList<>();
//入队列
queue.offer(root);
while(!queue.isEmpty()) {
//记录每层的节点
List<Integer> result=new LinkedList<>();
TreeNode node;
int size=queue.size();
//此时size是每层的节点个数
for(int i=0; i<size; i++) {
//出队列
node=queue.poll();
result.add(node.val);
if(node.left!=null) {
queue.offer(node.left);
}
if(node.right!=null) {
queue.offer(node.right);
}
}
res.add(result);
}
return res;
}
二叉树的层序遍历2
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res=new LinkedList<>();
Queue<TreeNode> queue=new LinkedList<>();
//入队列
if(root!=null) queue.offer(root);
else return res;
while(!queue.isEmpty()) {
//记录每层的节点
List<Integer> result=new LinkedList<>();
TreeNode node;
int size=queue.size();
//此时size是每层的节点个数
for(int i=0; i<size; i++) {
//出队列
node=queue.poll();
result.add(node.val);
if(node.left!=null) {
queue.offer(node.left);
}
if(node.right!=null) {
queue.offer(node.right);
}
}
res.add(result);
}
List<List<Integer>> ans=new LinkedList<>();
for(int i=res.size()-1; i>=0; i--) {
ans.add(res.get(i));
}
return ans;
}
二叉树的右视图
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res=new LinkedList<>();
Queue<TreeNode> queue=new LinkedList<>();
//入队列
if(root!=null) queue.offer(root);
else return res;
while(!queue.isEmpty()) {
//记录每层的节点
TreeNode node;
int size=queue.size();
//此时size是每层的节点个数
for(int i=0; i<size; i++) {
//出队列
node=queue.poll();
if(i==size-1)res.add(node.val);
if(node.left!=null) queue.offer(node.left);
if(node.right!=null) queue.offer(node.right);
}
}
return res;
}
还能用层序遍历解决一下问题:
- 637.二叉树的层平均值
- 429.N叉树的层序遍历
- 515.在每个树行中找最大值
- 116.填充每个节点的下一个右侧节点指针
- 117.填充每个节点的下一个右侧节点指针II
- 104.二叉树的最大深度
- 111.二叉树的最小深度
二叉树的最大深度
DFS和BFS都可以做
DFS代码:
int res=0;
public int maxDepth(TreeNode root) {
if(root==null)return 0;
dfs(root, res);
return res;
}
public void dfs(TreeNode root, int deep) {
if(root==null) {
res=Math.max(deep, res);
return;
}
dfs(root.left, deep+1);
dfs(root.right, deep+1);
}
翻转二叉树
这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次!
public TreeNode invertTree(TreeNode root) {
if(root==null)return null;
dfs(root);
return root;
}
public void dfs(TreeNode root) {
if(root==null)return;
TreeNode tmpNode=new TreeNode();
tmpNode=root.left;
left=root.right;
right=tmpNode;
dfs(root.left);
dfs(root.right);
}
对称二叉树
思路:第一种思路:是先将本来的树根节点存起来,然后翻转得到另一个新树,再同时对两棵遍历去比较结点的值是否相等,但是要遍历两次树,复杂度很高。
直接一次遍历就可以:可以以根节点为中心,相等于比较左子树、右子树的外侧是否相等,左子树、右子树的内测是否相等。
确定终止条件有一些复杂:自己想的时候总是会漏掉部分终止条件,但是递归这种东西终止条件一定要写对,否则不能AC。
要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚!否则后面比较数值的时候就会操作空指针了。
节点为空的情况有:(注意我们比较的其实不是左孩子和右孩子,所以如下我称之为左节点右节点)
- 左节点为空,右节点不为空,不对称,return false
- 左不为空,右为空,不对称 return false
- 左右都为空,对称,返回true
此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:
- 左右都不为空,比较节点数值,不相同就return false
public boolean isSymmetric(TreeNode root) {
if(root==null)return true;
return dfs(root.left, root.right);
}
public boolean dfs(TreeNode left, TreeNode right) {
if(left==null && right==null)return true;
else if(left==null && right!=null)return false;
else if(left!=null && right==null)return false;
else if(left.val!=right.val)return false;
else {
//比较内侧
boolean a=dfs(left.left, right.right);
//比较外侧
boolean b=dfs(left.right, right.left);
return a && b;
}
}
完全二叉树的节点个数
public int countNodes(TreeNode root) {
if(root==null) {
return 0;
}
else {
//这个+1是这道题的精髓,拿到此根结点就+1,再分别加上左、右节点的节点数
return countNodes(root.left)+countNodes(root.right)+1;
}
}