数据结构奇妙旅程之二叉平衡树进阶---AVL树

news2024/11/15 17:31:02

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱
ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶
个人主页:xiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
系列专栏:xiaoxie的JAVA系列专栏——CSDN博客●'ᴗ'σσணღ*
我的目标:"团团等我💪( ◡̀_◡́ ҂)" 

( ⸝⸝⸝›ᴥ‹⸝⸝⸝ )欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​+关注(互三必回)!

 一.AVL树的概念

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺 序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年 发明了一种 解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过 1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。 一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:

1.它的左右子树都是AVL树

2.左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

这里我们规定节点的左孩子的平衡因子为--,右孩子为++;

如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在 ,搜索时间复杂 度O(logN)。

二.AVL树节点的定义

public class AVLTree {
 public static class TreeNode {
     public int val; 
     public TreeNode left;
     public TreeNode right;
     public int bf;// 当前节点的平衡因子=右子树高度-左子树的高度
     public TreeNode parent;
     public TreeNode(int val) {
         this.val = val;
     }
 }
 public TreeNode root;

当前节点的平衡因子=右子树高度-左子树的高度。但是,不是每棵树,都必须有平衡因子,这只是其中的一种实现方式,并且这只是一种表示方式。

三.AVL树节点的插入

AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么AVL树的插入过程可 以分为两步:

1.按照二叉搜索树的方式插入新节点

 TreeNode node = new TreeNode(val);
     if(root == null) {
         root = node;
         root.parent = null;
     }
     TreeNode parent = null;
     TreeNode cur = root;
     while (cur != null) {
         if(node.val < cur.val) {
             parent = cur;
             cur = cur.left;
         } else if (node.val > cur.val) {
             parent = cur;
             cur = cur.right;
         }else {
             System.out.println("节点值 " + val + " 已经存在于树中,不进行插入操作");
             return false;
         }
     }
     //cur == null
      //找到node是parent的左孩子还是右孩子
      if(node.val < parent.val) {
          parent.left = node;
      }else {
          parent.right = node;
      }
      node.parent = parent;
      cur = node;

 2.调整节点的平衡因子

新节点插入后,AVL树的平衡性可能会遭到破坏,此时就需要更新平衡因子,并检测是否破坏了AVL树 的平衡性.

此时cur节点插入,parent节点的平衡因子就需要调整, 有以下两种情况

1.Cur插入到Parent的左侧,只需给Parent的平衡因子-1即可

2. 如果Cur插入到Parent的右侧,只需给Parent的平衡因子+1即可

此时:Parent的平衡因子可能有三种情况:0,正负1, 正负2

1.如果parent的平衡因子为0,那么就说明在插入前parent的平衡因子为正负1,插入后被调整成0,此时满足 AVL树的性质,插入成功

2.如果Parent的平衡因子为正负1,说明插入前Parent的平衡因子一定为0,插入后被更新成正负1,此 时以Parent为根的子树的高度增加,需要继续向上更新

3.如果Parent的平衡因子为正负2,则Parent的平衡因子违反平衡树的性质,需要对其进行旋转处理

  while (parent != null) {
          //计算节点的平衡因子
          //如果是左孩子就--
          //右孩子就++;
          if(cur == parent.left) {
              parent.bf--;
          }else {
              parent.bf++;
          }
          //根据不同的平衡因子有不同的情况
          //1.如果平衡因子为0
          if(parent.bf == 0) {
              break;
          } else if (parent.bf == 1 || parent.bf == -1) {
              cur = parent;
              parent = cur.parent;
          }else {
              if(parent.bf == 2) { //就代表右树高,需要调整右树的高度,就是左单旋,或者右左双旋
                  if(cur.bf == 1) {
                      rotateLeft(parent);
                  }else {
                      rotateRL(parent);//cur.bf = -1
                  }
              }else {//parent.bf == -2//就代表左树高,需要调整左树的高度,就是左单旋,或者左右双旋
                  if(cur.bf == 1) {
                      rotateLR(parent);
                  }else {//cur.bf == -1
                      rotateRight(parent);
                  }
              }
          }

 四.AVL树的旋转(重点)

如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,使之平衡化。根据 节点插入位置的不同,AVL树的旋转分为四种:

1.新节点插入较高左子树的左侧---右单旋

上图在插入前,AVL树是平衡的,新节点插入到20的左子树(注意:此处不是左孩子)中,20左子树增加 了一层,导致以60为根的二叉树不平衡,要让60平衡,只能将60左子树的高度减少一层,右子树增加一层, 即将左子树往上提,这样60转下来,因为60比30大,只能将其放在30的右子树,而如果30有右子树,右子树根的值 一定大于30,小于60,只能将其放在60的左子树,旋转完成后,更新节点的平衡因子即可。在旋转过程中,有以下 几种情况需要考虑: 1. 30节点的右孩子可能存在,也可能不存在 2. 60可能是根节点,也可能是子树 如果是根节点,旋转完成后,要更新根节点 如果是子树,可能是某个节点的左子树,也可能是右子树 

 /**
   * 右单旋左树高的话需要调整左树的高度
   * @author xiaoxie
   * @date 2024/3/6 15:01
   * @param parent
   */
  private void rotateRight(TreeNode parent) {
      TreeNode subL = parent.left;
      TreeNode subLR = subL.right;
      subL.right = parent;
      parent.left = subLR;
      if(subLR != null) {
          subLR.parent = parent;
      }
      TreeNode Pparent = parent.parent;
      parent.parent = subL;
      if(parent == root) {
          root = subL;
          root.parent = null;
      }else {
           if(Pparent.left == parent) {
              Pparent.left = subL;
          }else {
              Pparent.right = subL;
          }
          subL.parent = Pparent;
      }
      parent.bf = 0;
      subL.bf = 0;
  }

2. 新节点插入较高右子树的右侧---左单旋 

 

上图在插入前,AVL树是平衡的,新的节点80,插入到70的右子树,70右子树增加 了一层,导致以30为根的二叉树不平衡,要让30平衡,只能将30右子树的高度减少一层,左子树增加一层, 即将右子树往上提,这样30转下来,因为30比60小,只能将其放在60的左子树,而如果60有左子树,左子树根的值 一定大于30,小于60,只能将其放在30的右子树,旋转完成后,更新节点的平衡因子即可。在旋转过程中,有以下 几种情况需要考虑: 1. 60节点的右孩子可能存在,也可能不存在 2. 30可能是根节点,也可能是子树 如果是根节点,旋转完成后,要更新根节点 如果是子树,可能是某个节点的左子树,也可能是右子树 

/** 左单旋
   * 左旋,右树高的情况,需要调整右树的高度
   * @author xiaoxie
   * @date 2024/3/6 14:14
   * @param parent
   */
  private void rotateLeft(TreeNode parent) {
      TreeNode subR = parent.right;
      TreeNode subRL = subR.left;
      subR.left = parent;
      parent.right = subRL;
      if(subRL != null) {
          subRL.parent = parent;
      }
      //先记录parent节点的父亲节点
      TreeNode Pparent = parent.parent;
      parent.parent = subR;
      if(parent == root) {
          root = subR;
          subR.parent = null;
      }else {
          if(Pparent.left == parent) {
              Pparent.left = subR;
          }else {
              Pparent.right = subR;
          }
          subR.parent = Pparent;
      }
      parent.bf = 0;
      subR.bf = 0;
  }

3.新节点插入较高左子树的右侧:先左单旋再右单旋【左右双旋】

当一个节点的左子树比右子树高度高2个以上时,且这个节点的左子节点的右子树高于左子树时,需要进行左右双旋

1.情况一 subLR的平衡因子为1

 

在上图插入前,AVL树是平衡的,但在插入节点50后,插入到40的右子树上时,40的左子树的高度就增加一层了,以60为根的子树就不平衡了,这个时候我们就需要增加60的右子树的高度,降低左子树的高度,我们就需要用到右单旋,但60节点的左子节点的右子树高于左子树时,我们仅仅通过简单的右单旋并不能使这棵树变成高度平衡的二叉搜索树,我们就需要先进行左单旋,使这个节点的左节点的左子树和右子树的平衡后再进行右单旋,可以从上图看出,在进行左单旋后这颗树的情况和情况1一样,只是在最后需要我们调整 subL,parent,subLR的平衡因子即可

2.情况二subLR的平衡因子为-1

 

情况二和情况一的旋转过程大致一样,只不对 subL,parent,subLR的平衡因子的调整不同

/**
   * 左右双旋
   * @author xiaoxie
   * @date 2024/3/6 16:04
   * @param parent
   */
  private void rotateLR(TreeNode parent) {
      TreeNode subL = parent.left;
      TreeNode subLR = subL.right;
      int bf = subLR.bf;
      rotateLeft(parent.left);//左旋
      rotateRight(parent);//右旋
      if(bf == 1) {
          subLR.bf = 0;
          subL.bf = -1;
          parent.bf = 0;
      }else if(bf == -1) {
          subLR.bf = 0;
          subL.bf = 0;
          parent.bf = 1;
      }
  }

4.新节点插入较高右子树的左侧---右左:先右单旋再左单旋【右左双旋】

当一个节点的右子树比左子树高度高2个以上时,且这个节点的右子节点的左子树高于右子树时,需要进行右左双旋

1.情况一 subRL的平衡因子为1

 

在上图插入前,AVL树是平衡的,但在插入节点75后,插入到70的右子树上时,70的右子树的高度就增加一层了,以60为根的子树就不平衡了,这个时候我们就需要增加60的左子树的高度,降低右子树的高度,我们就需要用到左单旋,但60节点的右子节点的左子树高于右子树时,我们仅仅通过简单的左单旋并不能使这棵树变成高度平衡的二叉搜索树,我们就需要先进行右单旋,使这个节点的右节点的右子树和左子树的平衡后再进行左旋,可以从上图看出,在进行右单旋后这颗树的情况和情况2一样,只是在最后需要我们调整 subR,parent,subRL的平衡因子即可 

2.情况二subRL的平衡因子为-1

 

况二和情况一的旋转过程大致一样,只不对 subR,parent,subRL的平衡因子的调整不同

/**
   * 右左双旋
   * @author xiaoxie
   * @date 2024/3/6 16:19
   * @param parent
   */
  private void rotateRL(TreeNode parent) {
      TreeNode subR = parent.right;
      TreeNode subRL = subR.left;
      int bf = subRL.bf;
      rotateRight(parent.right);
      rotateLeft(parent);
      if(bf == -1) {
          parent.bf = 0;
          subR.bf = 1;
          subRL.bf = 0;
      }else if(bf == 1) {
          parent.bf = -1;
          subRL.bf = 0;
          subR.bf = 0;
      }
  }

 5.旋转的总结

新节点插入后,假设以Parent为根的子树不平衡,即Parent的平衡因子为2或者-2,分以下情况考虑

1. Parent的平衡因子为2,说明Parent的右子树高,设Parent的右子树的根为SubR 当SubR的平衡因子为1时,执行左单旋 当SubR的平衡因子为-1时,执行右左双旋

2. Parent的平衡因子为-2,说明Parent的左子树高,设Parent的左子树的根为SubL 当SubL的平衡因子为-1是,执行右单旋 当SubL的平衡因子为1时,执行左右双旋

即:Parent与其较高子树节点的平衡因子时同号时单旋转,异号时双旋转。

旋转完成后,原Parent为根的子树个高度降低,已经平衡,不需要再向上更新

五.总的代码实现及总结

1.Java代码实现

public class AVLTree {
 public static class TreeNode {
     public int val;
     public TreeNode left;
     public TreeNode right;
     public int bf;
     public TreeNode parent;
     public TreeNode(int val) {
         this.val = val;
     }
 }
 public TreeNode root;
 /**
  * 插入节点,并调整平衡因子
  * 使用旋转的方法调整平衡因子
  * @author xiaoxie
  * @date 2024/3/6 13:13
  * @param val
  * @return boolean
  */
  public boolean insertNode(int val) {
      TreeNode node = new TreeNode(val);
     if(root == null) {
         root = node;
         root.parent = null;
     }
     TreeNode parent = null;
     TreeNode cur = root;
     while (cur != null) {
         if(node.val < cur.val) {
             parent = cur;
             cur = cur.left;
         } else if (node.val > cur.val) {
             parent = cur;
             cur = cur.right;
         }else {
             System.out.println("节点值 " + val + " 已经存在于树中,不进行插入操作");
             return false;
         }
     }
     //cur == null
      //找到node是parent的左孩子还是右孩子
      if(node.val < parent.val) {
          parent.left = node;
      }else {
          parent.right = node;
      }
      node.parent = parent;
      cur = node;
      while (parent != null) {
          //计算节点的平衡因子
          //如果是左孩子就--
          //右孩子就++;
          if(cur == parent.left) {
              parent.bf--;
          }else {
              parent.bf++;
          }
          //根据不同的平衡因子有不同的情况
          //1.如果平衡因子为0
          if(parent.bf == 0) {
              break;
          } else if (parent.bf == 1 || parent.bf == -1) {
              cur = parent;
              parent = cur.parent;
          }else {
              if(parent.bf == 2) { //就代表右树高,需要调整右树的高度,就是左单旋,或者右左双旋
                  if(cur.bf == 1) {
                      rotateLeft(parent);
                  }else {
                      rotateRL(parent);//cur.bf = -1
                  }
              }else {//parent.bf == -2
                  if(cur.bf == 1) {
                      rotateLR(parent);
                  }else {//cur.bf == -1
                      rotateRight(parent);
                  }
              }
          }
      }
      return true;
  }
  /** 左单旋
   * 左旋,右树高的情况,需要调整右树的高度
   * @author xiaoxie
   * @date 2024/3/6 14:14
   * @param parent
   */
  private void rotateLeft(TreeNode parent) {
      TreeNode subR = parent.right;
      TreeNode subRL = subR.left;
      subR.left = parent;
      parent.right = subRL;
      if(subRL != null) {
          subRL.parent = parent;
      }
      //先记录parent节点的父亲节点
      TreeNode Pparent = parent.parent;
      parent.parent = subR;
      if(parent == root) {
          root = subR;
          subR.parent = null;
      }else {
          if(Pparent.left == parent) {
              Pparent.left = subR;
          }else {
              Pparent.right = subR;
          }
          subR.parent = Pparent;
      }
      parent.bf = 0;
      subR.bf = 0;
  }
  /**
   * 右单旋左树高的话需要调整左树的高度
   * @author xiaoxie
   * @date 2024/3/6 15:01
   * @param parent
   */
  private void rotateRight(TreeNode parent) {
      TreeNode subL = parent.left;
      TreeNode subLR = subL.right;
      subL.right = parent;
      parent.left = subLR;
      if(subLR != null) {
          subLR.parent = parent;
      }
      TreeNode Pparent = parent.parent;
      parent.parent = subL;
      if(parent == root) {
          root = subL;
          root.parent = null;
      }else {
           if(Pparent.left == parent) {
              Pparent.left = subL;
          }else {
              Pparent.right = subL;
          }
          subL.parent = Pparent;
      }
      parent.bf = 0;
      subL.bf = 0;
  }
  /**
   * 左右双旋
   * @author xiaoxie
   * @date 2024/3/6 16:04
   * @param parent
   */
  private void rotateLR(TreeNode parent) {
      TreeNode subL = parent.left;
      TreeNode subLR = subL.right;
      int bf = subLR.bf;
      rotateLeft(parent.left);
      rotateRight(parent);
      if(bf == 1) {
          subLR.bf = 0;
          subL.bf = -1;
          parent.bf = 0;
      }else if(bf == -1) {
          subL.bf = 0;
          parent.bf = 1;
          subLR.bf = 0;
      }
  }
  /**
   * 右左双旋
   * @author xiaoxie
   * @date 2024/3/6 16:19
   * @param parent
   */
  private void rotateRL(TreeNode parent) {
      TreeNode subR = parent.right;
      TreeNode subRL = subR.left;
      int bf = subRL.bf;
      rotateRight(parent.right);
      rotateLeft(parent);
      if(bf == -1) {
          parent.bf = 0;
          subR.bf = 1;
          subRL.bf = 0;
      }else if(bf == 1) {
          parent.bf = -1;
          subRL.bf = 0;
          subR.bf = 0;
      }
  }
    private int height(TreeNode root) {
        if(root == null) return 0;
        int leftH = height(root.left);
        int rightH = height(root.right);

        return leftH > rightH ? leftH+1 : rightH+1;
    }
    /**
     * 验证是否正确AVLTree
     * @author xiaoxie
     * @date 2024/3/6 16:49
     * @param root
     * @return boolean
     */
    public boolean isBalanced(TreeNode root) {
        if(root == null) return true;
        int leftH = height(root.left);
        int rightH = height(root.right);

        if(rightH-leftH != root.bf) {
            System.out.println("这个节点:"+root.val+" 平衡因子异常");
            return false;
        }

        return Math.abs(leftH-rightH) <= 1
                && isBalanced(root.left)
                && isBalanced(root.right);
    }
}

2.AVL树总结

AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度,即 logN。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要 维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改就不太适合。 

以上就是博主关于AVL树的全部总结了,希望能够对你有所帮助!

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1510690.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3588板子部署yoloV5

一 &#xff1a;准备 ubuntu linux X86_64系统 a.安装anaconda b.创建虚拟环境 python3.8 二&#xff1a; 下载rknn-toolkit2 传送门 unzip 解压文件夹 三&#xff1a;pt转onnx模型 四&#xff1a;onnx转rknn模型 a:cd到rknn-toolkit2-master/rknn-toolkit2/packag…

使用Java的等待/通知机制实现一个简单的阻塞队列

Java的等待/通知机制 Java的等待通知机制是多线程间进行通信的一种方式。 有三个重要的方法&#xff1a;wait()&#xff0c;notify() 和以及notifyAll() wait()&#xff1a;该方法用于让当前线程&#xff08;即调用该方法的线程&#xff09;进入等待状态并且释放掉该对象上的…

初级爬虫实战——伯克利新闻

文章目录 发现宝藏一、 目标二、简单分析网页1. 寻找所有新闻2. 分析模块、版面和文章 三、爬取新闻1. 爬取模块2. 爬取版面3. 爬取文章 四、完整代码五、效果展示 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不…

leetcode 热题 100_螺旋矩阵

题解一&#xff1a; 模拟&#xff1a;定义四个边界&#xff0c;指针按右下左上的顺序遍历&#xff0c;每遍历一条边&#xff0c;边界就减一&#xff0c;并且在某个方向没有可以遍历的数时直接返回。 import java.util.ArrayList; import java.util.List;class Solution {publi…

探索ChatGPT的前沿科技:解锁其在地理信息系统、气候预测、农作物生长等关键领域的创新应用

以ChatGPT、LLaMA、Gemini、DALLE、Midjourney、Stable Diffusion、星火大模型、文心一言、千问为代表AI大语言模型带来了新一波人工智能浪潮&#xff0c;可以面向科研选题、思维导图、数据清洗、统计分析、高级编程、代码调试、算法学习、论文检索、写作、翻译、润色、文献辅助…

云仓酒庄2024市场活动:稳扎稳打,继续前行,以消费者为中心

云仓酒庄2024市场活动&#xff1a;稳扎稳打&#xff0c;继续前行&#xff0c;以消费者为中心 随着酒类市场的日益繁荣与多样化&#xff0c;云仓酒庄&#xff0c;始终将消费者的需求与满意度置于首位。2024年&#xff0c;云仓酒庄将围绕消费者需求&#xff0c;继续深化市场活动…

未来艺术展览新趋势——3D线上画展如何创新展示?

一、艺术展示的数字化转型 随着科技的不断进步&#xff0c;3D线上画展作为艺术展示的新趋势&#xff0c;正逐渐改变着人们欣赏和购买艺术作品的方式。对于画家而言&#xff0c;3D线上画展不仅提供了一个全新的平台来展示他们的作品&#xff0c;还开辟了销售渠道&#xff0c;扩大…

提升网络效率与稳定性——网络流量监控系统和故障诊断工具的重要性

引言 在当今数字化时代&#xff0c;网络已经成为企业和个人生活中不可或缺的一部分。然而&#xff0c;网络的稳定性和性能常常面临各种挑战&#xff0c;如网络流量过载、故障和安全威胁等。为了应对这些问题&#xff0c;AnaTraf网络流量分析仪应运而生。本文将介绍AnaTraf的特点…

数组扩展方法(二)

以下将对Array.prototype上的方法进行整理&#xff0c;es5中数组遍历的方法在 数组扩展方法&#xff08;一&#xff09;可以查看 会改变原始数组 以下方法都在Array.prototype原型上 push 数组尾部插入元素shift 数组首部删除元素unshift 向数组首部添加元素pop 数组尾部删除…

群晖docker安装sql server

安装步骤 开启群晖 SSH&#xff0c;通过 SSH 工具连接到群晖&#xff0c;运行下面的命令拉取mssql 2019 镜像 sudo docker pull mcr.microsoft.com/mssql/server:2019-latest然后在 docker 中就可以看到该镜像&#xff1a; 在群晖 docker 共享文件夹中创建 mssql2009 文件夹 …

基于SpringBoot和PotsGIS的各省地震震发可视化分析

目录 前言 一、后台接口研发 1、控制层实现 2、Mapper访问层 3、空间查询分析 二、前端可视化展示 1、主体地图定义 2、行政区划列表定义 3、行政区划定位 三、数据分析 1、北京市 2、广东省 3、青海省 4、湖南省 总结 前言 在之前的博文中&#xff0c;我们…

centos安装hadoop启动问题解决方案

1、出现了问题localhost: ERROR: JAVA_HOME is not set and could not be found. *解决方案尝试&#xff1a; 修改hadoop-env.sh&#xff08;在etc/hadoop&#xff09; sudo gedit /usr/local/hadoop/etc/hadoop/hadoop-env.sh 将原本的JAVA_HOME 替换为绝对路径就可以了 #expo…

【C语言刷题】——初识位操作符

【C语言刷题】——初识位操作符 位操作符介绍题一、 不创建临时变量&#xff08;第三个变量&#xff09;&#xff0c;实现两个数的交换&#xff08;1&#xff09;法一&#xff08;2&#xff09;法二 题二、 求一个数存储在内存中的二进制中“一”的个数&#xff08;1&#xff0…

论文阅读:FCB-SwinV2 Transformer for Polyp Segmentation

这是对FCBFormer的改进&#xff0c;我的关于FCBFormer的论文阅读笔记&#xff1a;论文阅读FCN-Transformer Feature Fusion for PolypSegmentation-CSDN博客 1&#xff0c;整体结构 依然是一个双分支结构&#xff0c;总体结构如下&#xff1a; 其中一个是全卷积分支&#xff…

浏览器缓存 四种缓存分类 两种缓存类型

浏览器缓存 本文主要包含以下内容&#xff1a; 什么是浏览器缓存按照缓存位置分类 Service WorkerMemory CacheDisk CachePush Cache 按照缓存类型分类 强制缓存协商缓存 缓存读取规则浏览器行为 什么是浏览器缓存 在正式开始讲解浏览器缓存之前&#xff0c;我们先来回顾一…

【保姆级教程】JDK安装与环境变量配置

文章目录 第一步&#xff1a;下载JDK&#xff08;以1.8为例&#xff09;第二步&#xff1a;安装第三步&#xff1a;找到默认安装目录第四步&#xff1a;配置环境变量&#xff08;win10为例&#xff09; 大家可能会遇到的疑问&#xff1a;一个电脑可以安装多个版本的jdk没有问题…

头脑风暴法是什么?10个值得推荐的头脑风暴模板!

身处职场的你&#xff0c;想必对头脑风暴这个术语并不陌生&#xff0c;它可能是某个同事或者领导的口头禅&#xff0c;每当遇到需要给出方案的场景&#xff0c;头脑风暴或者“脑暴”就会从他们嘴里脱口而出&#xff0c;但你真的了解&#xff0c;头脑风暴是什么意思吗&#xff1…

力扣刷题日志-Day2 (力扣151、43、14)

151. 反转字符串中的单词 给你一个字符串 s &#xff0c;请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开 思路&#xff1a;根据题目大意&#xff0c;空格之间的就是一个单词&#xff0c;所以我们需要利用…

Sui与数据平台ZettaBlock达成合作,为其公测提供数据

Sui一向以闪电般的速度、无限水平扩展著称&#xff0c;现已迅速成为DeFi活动的重要场所。近期&#xff0c;数据平台ZettaBlock宣布在其开创性的Web3数据平台发布中&#xff0c;选择Sui作为基础集成合作伙伴之一。在ZettaBlock的开放测试版发布之际&#xff0c;构建者和开发者将…

【JAVA】HashMap扩容性能影响及优化策略

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 结语 我的其他博客 前言 在软件开发中&#xff0c;HashMap是一种常用的数据结构&#xff0c;但在处理大量数据时&#xff0c;其扩容…