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

꒰˃͈꒵˂͈꒱ 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树的全部总结了,希望能够对你有所帮助!

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CountDownLatch介绍和使用

1. CountDownLatch是什么 CountDownLatch 是 Java.util.concurrent 包中的一个同步工具类&#xff0c;用于控制线程的执行顺序。它的主要作用是让一个或多个线程等待其他线程完成操作后再继续执行。 2. CountDownLatch 类常用方法 CountDownLatch(int count) 是 CountDownLa…

Java学习笔记18——SQLite3数据库安装与使用

SQLite 是一个嵌入式 SQL 数据库引擎&#xff0c;它实现了一个自包含、无服务器、零配置、事务性 SQL 数据库引擎。 SQLite 的代码属于公共领域&#xff0c;因此可以免费用于任何商业或私人目的。 SQLite 是世界上部署最广泛的数据库&#xff0c;其应用程序数量之多&#xff0c…

Java随手记

equals和的区别 使用基本数据类型&#xff08;char&#xff0c;int&#xff0c;long等&#xff09;的时候&#xff0c;比较的是它们的值 使用引用数据类型的时候&#xff0c;比较的是地址 equals如果不重写&#xff0c;那么和 是没差别的 下面来看String的比较&#xff0c;这…

图像压缩神器:使用wxPython和Pillow快速压缩JPEG文件

导语&#xff1a; 在数字时代&#xff0c;我们经常处理大量的图像文件&#xff0c;无论是个人照片、网络图片还是工作中的设计素材。然而&#xff0c;随着图像数量的增多&#xff0c;存储和传输这些文件可能会成为一个挑战。幸运的是&#xff0c;我们可以利用Python编程和两个强…

混合测试写一写

题目 服务器IP地址规划&#xff1a;client&#xff1a;12.0.0.12/24&#xff0c;网关服务器&#xff1a;ens36:12.0.0.1/24、ens33&#xff1a;192.168.44.1/24&#xff0c;Web1&#xff1a;192.168.44.30/24&#xff0c;Web2&#xff1a;192.168.44.50/24&#xff0c;Nginx&am…

基于前后端分离技术做增删改查操作(SpringBoot+Mybatis Plus+Vue)

通过SpringBoot后端项目&#xff0c;mybatis plus&#xff0c;和前端Vue来实现前后端分离技术 第一步&#xff1a; 1、准备sql 本项目主要实现两张表的增删改查&#xff08;老师专业&#xff09;分页 CREATE TABLE teacher (id int(11) NOT NULL AUTO_INCREMENT,name varch…

日常超实用技巧(一)

目录 场景说明 mysql解决 excel解决 vscode插件解决 notepad解决 扩展解决 正则解决 自动录制宏解决 场景说明 平常在开发中有时会遇到一些字符串的规整或者格式化的操作,这点在操作数据库时经常常见,但是有的时候却有这种需求,就是我们的修改条件是某个查询条件的字…

第三方软件测评机构出具软件测试报告的流程简析

第三方软件测评机构是独立于软件开发方和需求方的第三者机构&#xff0c;负责对软件进行全面的评估和测试。独立存在使得出具的测试结果会更客观公正。相比之下&#xff0c;软件开发方进行的测评工作往往存在着主观性和局限性&#xff0c;很难全面评估软件的各个方面。 第三方…

Linux操作系统-06-进程与服务管理

使用ps命令查看进程。包括过滤进程信息 使用systemctl命令管理和运行Linux服务 进程&#xff08;Process&#xff09;&#xff1a;操作系统正在运行的应用程序。任意一个进程&#xff0c;都会消耗CPU和内存资源&#xff0c; 服务&#xff08;Service&#xff09;&#xff1a…

C# Onnx C2PNet 图像去雾 室外场景

目录 介绍 效果 模型信息 项目 代码 下载 C# Onnx C2PNet 图像去雾 室外场景 介绍 github地址&#xff1a;https://github.com/YuZheng9/C2PNet [CVPR 2023] Curricular Contrastive Regularization for Physics-aware Single Image Dehazing 效果 模型信息 Model P…

Docker安装Prometheus监控

环境初始化 关闭防火墙 setenforce 0 vim /etc/selinux/config ##################内部代码################### SELINUXdisabled #关闭防火墙 ############################################ 安装docker #卸载yum源之前的docker安装包 sudo yum remove docker docker-clie…

打算考PMP,需要准备什么?

PMP是什么考试&#xff1f;是PMI设立的项目管理资格认证考试&#xff0c;旨在评估和确认候选人是否具备在各种项目环境中领导和管理项目的能力。 pmp考试不算简单&#xff0c;考前也需要更详细的了解考试情况才能更好的备考。文章不是很长&#xff0c;主要是可以让你快速的了解…

TSINGSEE青犀视频AI方案:数据+算力+算法,人工智能的三大基石

背景分析 随着信息技术的迅猛发展&#xff0c;人工智能&#xff08;AI&#xff09;已经逐渐渗透到我们生活的各个领域&#xff0c;从智能家居到自动驾驶&#xff0c;从医疗诊断到金融风控&#xff0c;AI的应用正在改变着我们的生活方式。而数据、算法和算力&#xff0c;正是构成…

IntelliJ IDEA Dev 容器

​一、dev 容器 开发容器&#xff08;dev 容器&#xff09;是一个 Docker 容器&#xff0c;配置为用作功能齐全的开发环境。 IntelliJ IDEA 允许您使用此类容器来编辑、构建和运行您的项目。 IntelliJ IDEA 还支持多个容器连接&#xff0c;这些连接可以使用 Docker Compose …

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…

C++学习笔记:红黑树

红黑树 什么是红黑树红黑树的规则红黑树节点的定义红黑树的插入空树插入非空插入条件判断新插入的节点 cur 不为 root 且 parent->_col 为红就需要调整父节点为左 grandf->left parent当uncle节点为红色时,只需要进行颜色调整,即可当uncle为空 或 者存在但是为黑parent …

cnetos7 清理 journal 日志

journal 日志如果长时间不清理&#xff0c;会占用系统很多空间&#xff0c;所有需要清理占用过多的一些日志。 1、查看journal日志当前使用情况&#xff0c;包括占用的磁盘空间、日志数量 journalctl --disk-usage 2、清除 journal 日志中超过 100MB 大小的内容 journalctl -…

Lord 3DMCV7-AHRS 时间同步硬件触发设置

目的:通过FPGA发送脉冲触发IMU采集数据。FPGA发送脉冲时,IMU才有数据产生。 FPGA与IMU的硬件接线就不讲了,这里主要说明的是IMU的设置以及ROS驱动的config文件更改。 1. WIN上位机设置 通过IMU在WINDOWS的上位机SensorConnect对IMU的GPIO、波特率等基本功能进行设值,具体…

项目解决方案:视频监控接入和录像系统设计方案(下)

目 录 1.概述 2. 建设目标及需求 2.1建设总目标 2.2 需求描述 ​2.3 需求分析 3.设计依据与设计原则 3.1设计依据 3.2 设计原则 4.建设方案设计 4.1系统方案设计 4.2组网说明 5.产品介绍 5.1视频监控综合资源管理平台介绍 5.2视频录像服务器和存储 5.2.…

SpringController返回值和异常自动包装

今天遇到一个需求&#xff0c;在不改动原系统代码的情况下。将Controller的返回值和异常包装到一个统一的返回对象中去。 例如原系统的接口 public String myIp(ApiIgnore HttpServletRequest request);返回的只是一个IP字符串"0:0:0:0:0:0:0:1"&#xff0c;目前接口…