1.对二叉树进行简单的复习。
1.普通二叉树
- 每个节点至多只有两个子树(即不存在度大于2的节点)。
基本形态
- 五种
A.空二叉树 B.只有根节点 C.只有左子树 D.只有右子树
E.左右子树都有
遍历方式
个人觉得树的遍历或者做关于树的的题目,一定不要陷下去,要从宏观的角度去看待。
不管那颗树多深多长,明确只有根节点,左节点,右节点。
a.先序遍历 本质:根->左->右
顺序:
根 | 左子树 | 右子树 |
---|---|---|
1 | 2,3 | 4,5,6,7,8,9 |
宏观上看
微观上看
这里的7肯定就在8前面了。
以下同理
b.中序遍历 本质:左->根->右
左子树 | 根 | 右子树 |
---|---|---|
2,3 | 1 | 5,4,7,8,6,9 |
宏观上看
c.后序遍历 本质:左->右->根
左子树 | 右子树 | 根 |
---|---|---|
3,2 | 5,8,7,9,6,4 | 1 |
宏观上看
d.层序遍历 按树的层数来进行
1,2,4,3,5,6,7,9,8
e.建立
本质:不断的查找(根)结点,进行插入的过程。
下面是 前序遍历加中序遍历 建立的二叉树(前序只知道根节点,还需中序确认左右子树大小,这里也可用其他搭配)
private static HashMap<Integer, Integer> indexMap;
public static TreeNode buildTree(int[] pre, int[] in) {
int n = pre.length;
indexMap = new HashMap<Integer, Integer>();
for (int i = 0; i < n; i++) {
indexMap.put(in[i], i);
// 1.构造中序哈希映射,帮助我们快速定位根节点
//2.定位到中序根节点就可求出左右大小
}
return Build(pre, in, 0, n - 1, 0, n - 1);
}
public static TreeNode Build(int[] pre, int[] in, int pre_left, int pre_right, int in_left, int in_right) {
if (pre_left > pre_right) {
return null;
}
// 前序遍历中的第一个节点就是根节点
int pre_root = pre_left;
// 在中序遍历中定位根节点
int in_root = indexMap.get(pre[pre_root]);
//本质上建立根节点,然后进行拼接
TreeNode root = new TreeNode(pre[pre_root]);
// 得到左子树中的节点数目
//[->左<-,根,右]
int size = in_root - in_left;
//root.左树=前:[根,->左<-,右]+ 中:[->左<-,根,右]
root.left = Build(pre, in, pre_left + 1, pre_left + size, in_left, in_root - 1);
//root.右树=前:[根,左,->右<-]+ 中:[左,根,->右<-]
root.right = Build(pre, in, pre_left + size + 1, pre_right, in_root + 1, in_right);
//宏观上就已经建好了,剩下的只是子问题了
return root;
}
//前序遍历
public static void PreOrder(TreeNode T) {
if (T != null) {
System.out.print(T.val + " ");
PreOrder(T.left);
PreOrder(T.right);
}
}
//中序遍历
public static void inOrder(TreeNode T) {
if (T != null) {
inOrder(T.left);
System.out.print(T.val + " ");
inOrder(T.right);
}
}
//后续遍历
public static void hostOrder(TreeNode T) {
if (T != null) {
hostOrder(T.left);
hostOrder(T.right);
System.out.print(T.val + " ");
}
}
//层序遍历
public static void levelOrder(TreeNode T) {
Queue<TreeNode> q = new LinkedList<>();//队列先进先出
q.add(T);//头入队
while (!q.isEmpty()) {
int k = q.size();
for (int i = 0; i < k; i++) {
TreeNode t = q.poll();
System.out.print(t.val + " ");
if (t.left != null)
q.add(t.left);
if (t.right != null)
q.add(t.right);
}
}
}
public static void main(String[] args) {
int[] per = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] in = {2, 3, 1, 5, 4, 7, 8, 6, 9};
TreeNode tree = new TreeNode();
tree = buildTree(per, in);
System.out.print("前序遍历:");
PreOrder(tree);
System.out.println();
System.out.print("中序遍历:");
inOrder(tree);
System.out.println();
System.out.print("后序遍历:");
hostOrder(tree);
System.out.println();
System.out.print("层序遍历:");
levelOrder(tree);
}
}
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;
}
}
二叉排序树
a.二叉排序树
1.别名:二叉搜索树,二叉查找树
2.左子树节点值<根节点值<右子树节点值
3.对其进行中序遍历,可得到一个递增序列
**1.查找:就像二分查找一样。例如查找2.
**2.插入:**找到合适位置的位置。新插入的数据一般都是在叶子节点上。例如插入1
3.删除
有三种情况
1.要删除的节点,没有孩子,那就直接删除。删1
2.要删除的节点,只有左孩,或者右孩。删2
3.要删除的节点,左右孩都有。删除30
说明:先找到这个节点的右子树中的最小节点35,把他替换到要删除的节点。最后删掉这个最小节点。
4.代码
public class Search {
public static void main(String[] args) {
TreeNode root=new TreeNode();
int[] k = {5,3,6,2,4,7};
for (int i = 0; i < k.length; i++) {
Insert(root,k[i]);//插入
if(Find(root,k[i]))//查找
System.out.println(k[i]+":插入成功");
}
root=Delete(root,2);
if(!Find(root,2))//查找
System.out.println(2+":删除成功");
}
public static void Insert(TreeNode root,int key){//插入
if(root==null){
root=new TreeNode(key);
return ;
}
TreeNode p=root;
while(p!=null) {//遍历然后插入
if(p.val>key)//放到左边
{
if(p.left==null){
p.left=new TreeNode(key);
return ;
}
p=p.left;
}
else if(p.val<key)//放到右边
{
if(p.right==null){
p.right=new TreeNode(key);
return ;
}
p=p.right;
}
else if(p.val==key)
return ;
}
}
public static boolean Find(TreeNode root,int key){//查找
while(root!=null){
if(root.val==key)
return true;
else if(root.val>key)
root=root.left;
else
root=root.right;
}
return false;
}
public static TreeNode Delete(TreeNode root, int key) {
TreeNode root1 = root;//记录要删除数字的那个节点
TreeNode root1_farther = null;//记录root1的父节点
while (root1 != null && root1.val != key) {
root1_farther = root1;
if (key > root1.val) root1 = root1.right;
else root1 = root1.left;
}
//要删除的数字找不到
if (root1 == null)
return root;
//如果要删除的左右都有,那就让它变成1,2那种情况。
if (root1.left != null && root1.right != null) {
TreeNode min = root1.right;
TreeNode min_farther = root1;
while (min.left != null) {//找右子树那个最小的
min_farther = min;
min = min.left;
}
root1.val = min.val;
root1 = min;//这个就是要删除的东西
root1_farther = min_farther;
}
//开始确认要删除的数字的孩子情况。
//这里删除的就是root1这个节点
TreeNode child = null;//用来记录要删除的root1的下面那些东西。
if (root1.left != null)
child = root1.left;
else if (root1.right != null)
child = root1.right;
else if(root1.left==null&&root.right==null)
child = null;
//遇到删除根节点的情况
if (root1_farther == null)
root = child;
//要删除的在左边
else if (root1_farther.left == root1)
root1_farther.left = child;
//要删除的在右边
else root1_farther.right = child;
return root;
}
}
满二叉树
高度为h,有由2^h-1个节点构成的二叉树。
完全二叉树
除了最后一层都满了,并且最后一层的所有节点都集中在最左边。
平衡二叉树(AVL树)
平衡二叉搜索树(英语:Balanced Binary Search Tree)是一种结构平衡的二叉搜索树,它是一种每个节点的左右两子树**高度差都不超过一的二叉树。**它能在O({\displaystyle \log n}\log n)内完成插入、查找和删除操作,最早被发明的平衡二叉搜索树为AVL树。
常见的平衡二叉搜索树有:
- AVL树
- 红黑树
- Treap
– 来自维基百科。
若有错误,还请指正。