文章目录
满二叉树和完全二叉树
满二叉树:如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树。
- 满二叉树中第 i 层的节点数为 2n-1 个。
- 深度为 k 的满二叉树必有 2k-1 个节点 ,叶子数为 2k-1。
- 满二叉树中不存在度为 1 的节点,每一个分支点中都两棵深度相同的子树,且叶子节点都在最底层。
- 具有 n 个节点的满二叉树的深度为 log2(n+1)。
完全二叉树:如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。
- 当 i>1 时,父亲结点为结点 [i/2] 。(i=1 时,表示的是根结点,无父亲结点)
- 如果 2i>n(总结点的个数) ,则结点 i 肯定没有左孩子(为叶子结点);否则其左孩子是结点 2i 。
- 如果 2i+1>n ,则结点 i 肯定没有右孩子;否则右孩子是结点 2i+1 。
二叉树的遍历
二叉树的先序,中序和后序遍历
import java.util.*;
/*
* public class TreeNode {
* int val = 0;
* TreeNode left = null;
* TreeNode right = null;
* }
*/
public class Solution {
//先序遍历
void preOrder(TreeNode root,ArrayList<Integer> list1){
if(root==null){
return;
}
list1.add(root.val);
preOrder(root.left,list1);
preOrder(root.right,list1);
}
//中序遍历
void inOrder(TreeNode root,ArrayList<Integer> list2){
if(root==null){
return;
}
inOrder(root.left,list2);
list2.add(root.val);
inOrder(root.right,list2);
}
//后序遍历
void postOrder(TreeNode root,ArrayList<Integer> list3){
if(root==null){
return;
}
postOrder(root.left,list3);
postOrder(root.right,list3);
list3.add(root.val);
}
}
层序遍历
用队列实现
import java.util.ArrayList;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
import java.util.*;
public class Solution {
ArrayList<Integer> Print(TreeNode pRoot) {
Queue<TreeNode> queue =new LinkedList();
ArrayList<Integer> arr=new ArrayList<>();
queue.add(pRoot);
TreeNode node;
while(queue.size()!=0){
node=queue.poll();
arr.add(node.val);
if(node.left!=null) queue.add(node.left);
if(node.right!=null) queue.add(node.right);
}
return arr;
}
}
二叉树的深度
把二叉树打印成多行
从上往下打印二叉树
按之字形打印二叉树:有一点不同,当为偶数层时,添加的时候用list(index,T)方法,这样T元素会插到index位置,而原index位置以及后面的会自动往后移。这样完成了倒着存储。
二叉搜索树BST(又称二叉排序树、二叉查找树)
一种有序二叉树,如果根节点左子树不为空,则该左子树上的所有节点值都小于根节点的值,如果右子树不为空,则该右子树上的所有节点值都大于该节点的值。如果按中序遍历,则是一个从小到大的有序数组
如何找到前驱节点和后继节点
- 前驱节点: 左子树的最右(最大)节点
- 后继节点: 右子树的最左(最小)节点
删除结点
- 该删除的节点无左右节点:直接删除
- 该节点有左节点:把左节点赋给该节点的父节点的子节点
- 该节点有右节点:把右节点赋给该节点的父节点的子节点
- 该节点有右节点和左节点:
1、找到该节点的后继节点(右子树的最左节点),把后继节点放在该处,然后删除后继节点(后继节点有可能没有子节点,直接删除,还有可能有右节点,则把右节点赋给该节点的父节点的子节点(同上第三点))
2、找到该节点的前驱节点(左子树的最右节点),把前驱节点放在该处,然后删除前驱节点(前驱节点有可能没有子节点,直接删除,还有可能有左节点,则把左节点赋给该节点的父节点的子节点(同上第二点))
平衡二叉树AVL和红黑树RBT
为什么要有AVL和RBT
大多数二叉排序树BST都是O(h)的时间复杂度,h为树的高度,但对于斜树而言(BST极端情况),BST这些操作时间复杂度将达到O(n),为了保证BST的所有操作的时间复杂度的上限为O(logn) ,就要想办法把一颗BST树的高度一直维持在O(logn),而AVL和RBT就做到了这一点,AVL和RBT的高度始终都维持在logn,n 为树中的顶点数目。
AVL
- 每个节点最多只有两个子节点(二叉树)
- 每个节点的值比它左子树左右节点大2,比它右子树左右节点小(有序)
- 每个节点左子树与右子树高度差不超过1
旋转
- 左左:右旋
- 左右:先左旋再右旋
- 右右:左旋
- 右左:先右旋再左旋
RBT
- 每个节点不是黑色就是红色
- 根节点为黑色
- 红色节点的父节点和子节点不能为红色
- 所有的叶子节点都是黑色(空节点视为叶子节点NIL)
- 每个节点到叶子节点的每个路径黑色节点的个数都相等。
每个插入的节点都视为红色
黑高
在一颗红黑树中,从某个结点 x 出发(不包含该结点)到达一个叶结点的任意一条简单路径上包含的黑色结点的数目称为 黑高 ,记为 bh(x) 。
红黑树的黑高则为其根结点的黑高。
变色
- 如果父节点和叔节点都是红色,则同时变为黑色,然后递归网上变色,根节点为黑色。
旋转
都是父为红,叔为黑的情况
- 左左:父为左节点,该节点也为左节点,右旋,变色
- 左右:父为左节点,该节点为右节点,先左旋,再右旋,再变色
- 右右:父为右节点,该节点也为右节点,左旋,变色
- 右左:父为右节点,该节点为左节点,先右旋,再左旋,再变色
AVL和RBT的区别
- AVL左右子树高度不超过1,RBT可能会超过1
- AVL不平衡进行旋转,RBT不平衡可能只变色,不旋转
- AVL比RBT更加平衡,AVL在插入和删除时存在大量的选择操作,所以涉及到频繁的插入和删除操作时,应放弃AVL,选择性能更好的红黑树
- AVL适合查找多,RBT适合修改多