class 032 位图

这篇文章是看了“左程云”老师在b站上的讲解之后写的, 自己感觉已经能理解了, 所以就将整个过程写下来了。

这个是“左程云”老师个人空间的b站的链接, 数据结构与算法讲的很好很好, 希望大家可以多多支持左程云老师, 真心推荐.

左程云的个人空间-左程云个人主页-哔哩哔哩视频 (bilibili.com)

在这里插入图片描述

1. 位图的原理

位图是一个类似于哈希表的“集合结构”,

哈希表可以放置不同的整数, 一个整数占据一个 int(32个bit位).无论是放 1 还是 10亿, 都是占据 32个bit位. 可以放置很多的数字,

位图和哈希表类似, 而且极大的节省了空间, 一个数字只占据 一个 bit位, 但是不能放置太多的数字, 而且要保证所有数字必须是一个连续的区间.

对比:在这里我们只是探讨(int)整数类型的.

  1. 数据要求:
    1. 哈希表:不用是连续的整数, 任何数字都可以, 1, 3, 20亿. 任何数字都能随机加入哈希表.
    2. 位图:必须是一段连续的整数比如:0 ~ 200万, 确定了之后不能有其余的数字加入位图. 要是我们只是加入 1 和 20亿 这两个数字, 使用位图, 这就需要创建一个很巨大的数组, 空间上反而不划算了, 所以需要一个连续的区间.
  2. 占据空间
    1. 哈希表:一个数字占据一个 int(32个bit位) 空间
    2. 位图:一个数字占据一个 bit位 空间. 极大地节省了空间.
  3. 效率高低
    1. 哈希表:各种操作的平均时间复杂度是 O(1), 但是最坏情况有可能到达 O(n).
    2. 位图:各种操作的时间复杂度是 O(1), 是确定的.

注意:位图在使用的之前, 必须要先给定范围, 比如给定的范围是:0 ~ 1000, 在初始化的时候就能确定范围了. 以后所有数字(0 ~ 1000)进来的时候就不会额外占据空间了, 加入我想要放入 1234 这个数字, 是不能放入的, 因为不在这个范围内.

1.1 原理实现

假设此时我们需要存储 0 ~ 100 之间的数字, 一个 int 类型有 32个bit位,
所以 32(int) * 4 == 128 > 100, 所以我们可以知道需要 4int 类型来存储.

int:[a][b][c][d], 此时我们创建了 1int 类型的数组, 长度为: 4 , 我们可以用来存储 1 ~ 100 之间的数字了, a(0 ~ 31), b(32 ~ 63), c(64 ~ 95), d(96 ~ 127). 这样就能进行存储了.

我们利用每一个 bit位, 要是 bit位1 说明对应的数字存在, 是 0 就代表对应的数字不存在.

从这里就能看出来, 位图极大地节省了空间, 非常方便. 我们只是用了 int[4] 就表示好了.

1.2 如何找到对应的位置

我们还是按照上面的数据:我们创建一个数字 int[4], 下标是 0, 1, 2, 3.

假设我们要找一个数字 x 对应的位置, 应该让 x / 32 这样找到的就是对应的 int 位置.
如果找找到这个数字在 int位置 中对应的 bit 位, 就直接让 x % 32.

举一个具体例子:假设我们要找 66 这个数字,
我们先找到它在哪一个下标:66 / 32 == 2, 所以在下标为 2int 位置.
然后我们找 66 在哪一个 bit位66 % 32 == 2, 所以在第二个位置 我们认为还是0, 1, 2 所以是第二个位置.(说第三个位置也是可以的, 但是我们这里就为了统一就直接说第二个位置).\

在这里插入图片描述

2. 位图的各种操作的实现

2.1 位图的各种操作

在这里插入图片描述

2.2 位图各种操作的实现

2.2.1 位图的初始化(利用构造函数)

这个意味着位图的初始化, 先给我一个数字 n, 位图需要存储的范围是:[0, n - 1]. 举几个例子说明:

  1. 假设 n == 1, 需要存储的范围是:[0, 0] 那我需要有一个 int(32位) 类型的空间. 这是最低标准
  2. 假设 n == 2 , 需要存储的范围是:[0, 1] 那我也需要有一个 int(32位) 类型的空间.
  3. 假设 n == 32 , 需要存储的范围是:[0, 31] 那我也需要有一个 int(32位) 类型的空间.
  4. 假设 n == 33 , 需要存储的范围是:[0, 32] 那我也需要有两个 int(32位) 类型的空间. 因为我第一个 int 类型的只能存放 [0, 31], 必须开辟下一个 int 空间用来存储 32 这个整数.
  5. 所以 1 / 32(向上取整) == 1, 2 / 32(向上取整) == 1, 33 / 32(向上取整) == 2.

总结:我们需要向上取整.

向上取整用代码实现如下:

原理:只是涉及到 a 和 b 的值(前提是 a, b 都是非负数), 利用这个式子:(a+b-1)/b

  1. 要是 a == k * b + 小余数, 不管这个余数是多少, 之后进行 + (b - 1), 都能实现向上取整的效果.
  2. 要是 a == k * b, 也能实现向上取整的效果, 只是没有变化.(假设 a = b = 3, 此时 a/b == 1), 没有实现向上取整的必要和意义. 但是使用上面的式子:5/3 == 1, 和原来是一样的.
public int[] set;  
  
// n个数字 : 0~n-1public Bitset(int n) {  
    // a/b如果结果想向上取整,可以写成 : (a+b-1)/b    // 前提是a和b都是非负数  
    set = new int[(n + 31) / 32];  // 这样就足以支持 n - 1 个数字了.
}

2.2.2 位图的加入操作 add 函数

  1. 我们先要找到 num 这个数字在数组的哪一个下标(位置)中, 利用:num / 32.
  2. 然后寻找到在这个位置中的哪一个 bit位:利用 num % 32.
  3. 找到之后, 将这个 bit位0 修改为 1.

举一个例子:

按照 8 个bit位来举例:
10101100 我们要将第 4 个位置的数字修改为 1 , 按照从右往左 0 ~ 31.
00010000 我们将 1 这个数字左移:(num % 32) 个 bit 位.
-------- | 进行“按位或”运算
10111100 这样就将“bit”位修改了.

实际操作代码如下:

public void add(int num) {  
    set[num / 32] |= 1 << (num % 32);  // 为了使代码更加简洁.
    // set[num / 32] 是数组中的下标, 第几个位置.
}

在这里插入图片描述

2.2.3 位图的删除操作 remove 函数

add 的操作是一样的,

  1. 我们先要找到 num 这个数字在数组的哪一个下标 (位置) 中, 利用:num / 32.
  2. 然后寻找到在这个位置中的哪一个 bit位:利用 num % 32.
  3. 找到之后, 将这个 bit位1 修改为 0.

还是举一个例子:

按照 8 个bit位来举例:
10101100 我们要将第 3 个位置的数字修改为 0 , 按照从右往左 0 ~ 31.
00001000 我们将 1 这个数字左移:(num % 32) 个 bit 位.

11110111 这里我们将这个数字进行取反操作 ~(1 << (num % 32)).
10101100 和原来的数字进行 & 操作.
-------- &
10100100 这样就将数字 1 修改为:0.

实际操作代码如下:

注意:推荐使用这个方法, 虽然用 ^ 运算也能做, 但是有缺陷,

  1. 使用 & 运算:不用进行判断, 无论需要修改的位置是不是 0, 我都能将其修改为 0.
  2. 使用 ^ 运算:需要进行判断, 若是需要修改的位置是 0, 那就修改为了 1.(会出现错误), 所以推荐下面这个使用 & 运算的方法.
public void remove(int num) {  
    set[num / 32] &= ~(1 << (num % 32));  
}

2.2.4 位图的反转操作 reverse 函数

reverse 函数实现的是:

  1. 若是一个数字在位图中, 通过 reverse 函数消除这个数字, (将对应的 bit位1 修改为 0)
  2. 若是一个数字不在位图中, 通过 reverse 函数添加这个数字, (将对应的 bit位0 修改为 1)

这个需要注意的地方和 remove 中的一样, 已经说的很明白了.

举一个例子:

11110111 我们举一个极端一点的例子:我们需要修改的是第 3 个位置的 0.(假设这个位置是 0 即:没有这个数字).
00001000 我们将 1 这个数字左移:(num % 32) 个 bit 位.
-------- ^
11111111 这样就修改好了.

11111111 我们继续利用这个例子, 修改第 3 个位置的 1, (这个位置的数字是 1 即:有这个数字)
00001000 我们将 1 这个数字左移:(num % 32) 个 bit 位.
-------- ^
11110111 这样就修改好了.

实际操作代码如下:

public void reverse(int num) {  
    set[num / 32] ^= 1 << (num % 32);  
}

2.2.5 位图的检查 contains 函数

我们判断一个数字 num 在不在位图中, 只需要判断对应的 bit位1 还是 0 就行了.

num / 32 和 num % 32 的意义就不说了,

有两种方法:

  1. 将对应数字的对应 bit位 向右移动到 0 位置, 然后和 1 进行 & 运算, 判断 结果是不是 == 1 就行
    1. 对应的代码:((set[num / 32] >> (num % 32)) & 1) == 1.
  2. 1 向左移动到对应的需要判断的 bit位 位置, 然后进行 & 运算, 判断 结果是不是 != 0 就行.
    1. 对应的代码:(set[num / 32] & (1 << (num % 32))) != 0.
public boolean contains(int num) {  
    return ((set[num / 32] >> (num % 32)) & 1) == 1;  
}

3. 对数器验证正确性

这里直接将所有的代码都打出来:

import java.util.HashSet;  
  
// 位图的实现  
// Bitset(int size)  
// void add(int num)  
// void remove(int num)  
// void reverse(int num)  
// boolean contains(int num)  
public class Code01_Bitset {  
  
    // 位图的实现  
    // 使用时num不要超过初始化的大小  
    public static class Bitset {  
       public int[] set;  
  
       // n个数字 : 0~n-1       public Bitset(int n) {  
          // a/b如果结果想向上取整,可以写成 : (a+b-1)/b          // 前提是a和b都是非负数  
          set = new int[(n + 31) / 32];  
       }  
  
       public void add(int num) {  
          set[num / 32] |= 1 << (num % 32);  
       }  
  
       public void remove(int num) {  
          set[num / 32] &= ~(1 << (num % 32));  
       }  
  
       public void reverse(int num) {  
          set[num / 32] ^= 1 << (num % 32);  
       }  
  
       public boolean contains(int num) {  
          return ((set[num / 32] >> (num % 32)) & 1) == 1;  
       }  
  
    }  
  
    // 对数器测试  
    public static void main(String[] args) {  
       int n = 1000;  
       int testTimes = 10000;  
       System.out.println("测试开始");  
       // 实现的位图结构  
       Bitset bitSet = new Bitset(n);  
       // 直接用HashSet做对比测试  
       HashSet<Integer> hashSet = new HashSet<>();  
       System.out.println("调用阶段开始");  
       for (int i = 0; i < testTimes; i++) {  
          double decide = Math.random();  
          // number -> 0 ~ n-1,等概率得到  
          int number = (int) (Math.random() * n);  
          if (decide < 0.333) {  
             bitSet.add(number);  
             hashSet.add(number);  
          } else if (decide < 0.666) {  
             bitSet.remove(number);  
             hashSet.remove(number);  
          } else {  
             bitSet.reverse(number);  
             if (hashSet.contains(number)) {  
                hashSet.remove(number);  
             } else {  
                hashSet.add(number);  
             }  
          }  
       }  
       System.out.println("调用阶段结束");  
       System.out.println("验证阶段开始");  
       for (int i = 0; i < n; i++) {  
          if (bitSet.contains(i) != hashSet.contains(i)) {  
             System.out.println("出错了!");  
          }  
       }  
       System.out.println("验证阶段结束");  
       System.out.println("测试结束");  
    }  
  
}

3.1 解释对数器的验证过程

提醒:对数器是一个极其重要的验证手段和 debug 练习方式, 所以一定要掌握, 一定要多熟悉, 多写对数器.

重点是解释对数器的验证过程:

  1. 原理是:使用哈希表和位图进行对比, 两个类能实现的功能是一样的, 所以只需要判断最后的结果是不是一样就行了.
  2. 首先设置 n 的范围, 然后设置 测试次数:testTimes. 创建位图和哈希表的实例
  3. 每一次测试都随机生成 number 的值(范围是:[0, 999]), 然后每一次都随机生成 decide 的值(范围是 [0, 1)).
  4. 然后根据 decide 的范围来判断执行哪一步操作. 这里我们设置的是,
    1. 若是 < 0.333(近似约等于 1/3 的概率), 就将 number 同时加入哈希表和位图中.
    2. 若是 >= 0.333 && < 0.666, 就将 number 从哈希表和位图中删除.
    3. 若是 >= 0.666 < 1, 就执行位图的反转操作, hashset 内置函数中没有这个功能的函数, 自己实现就行了, 比如分为两种情况:先用 hashsetcontains 函数判断是不是存在这个数字,
      1. 要是存在就删除.
      2. 要是不存在就加入.
  5. 然后进行验证过程:因为我们先设置的 n == 1000, 所以位图和哈希表中能进行存储的数字范围是:[0, 999], 所以对应的, 从 0 开始, 判断是不是存在于哈希表和位图中, 要是存在肯定是同时存在, 要是不存在肯定同时不存在, 因为返回的类型是 boolean类型, 所以只需要判断最后 true 和 false 能不能对上 就行.

4. 实现更多操作并且在线测试验证

在这里插入图片描述

// 位图的实现  
// Bitset是一种能以紧凑形式存储位的数据结构  
// Bitset(int n) : 初始化n个位,所有位都是0  
// void fix(int i) : 将下标i的位上的值更新为1  
// void unfix(int i) : 将下标i的位上的值更新为0  
// void flip() : 翻转所有位的值  
// boolean all() : 是否所有位都是1  
// boolean one() : 是否至少有一位是1  
// int count() : 返回所有位中1的数量  
// String toString() : 返回所有位的状态  
public class Code02_DesignBitsetTest {  
  
    // 测试链接 : https://leetcode-cn.com/problems/design-bitset/    
    class Bitset {  
       private int[] set;         // 初始化时需要使用的数组  
       private final int size;    // 判断到底要支持几个数字的查询, 在初始化的时候是多少, 后续就永远确定了.  
       private int zeros;         // 判断有几个不存在的:不存在的数字的数量  
       private int ones;          // 判断有几个存在的:存在的数字的数量  
       private boolean reverse;   // 是否整个位经历过反转.若是 reverse = false 说明:1 代表:存在, 0 代表:不存在.  
                                         // 若是 reverse = true 说明:1 代表:不存在, 0 代表:存在.  
                                         // 这样会非常方便, 不用整体进行遍历一遍修改.  
  
       public Bitset(int n) {  
          set = new int[(n + 31) / 32];  // 这个和原来一样, 还是向上取整.  
          size = n;            // 代表了可以进行 n 个数字的查询.  
          zeros = n;           // 因为最开始位图中全是:0, 所以设置为 n.          
          ones = 0;            // 因为最开始位图中全是:0, 所以设置为 0, 没有 1.          
          reverse = false;     // 此时没有经历过反转, 所以 reverse 是 false.       
          }  
  
       // 把i这个数字加入到位图  
       public void fix(int i) {  
          int index = i / 32;  
          int bit = i % 32;  
          if (!reverse) {  
             // 位图所有位的状态,维持原始含义  
             // 0 : 不存在  
             // 1 : 存在  
             if ((set[index] & (1 << bit)) == 0) { // 这里说明需要添加的位置 bit位 是:0.需要添加数字.  
                zeros--;   // 0 的数量要 “--”, 因为一个新的数字进来了.  
                ones++;    // 1 的数量要 “++”, 因为一个新的数字进来了.  
                set[index] |= (1 << bit);  
             }      // else 情况就说明 bits位 是 1, 不需要添加数字. 那就不用操作 else 情况了.  
          } else {   // 反转之后的情况.  
             // 位图所有位的状态,翻转了  
             // 0 : 存在  
             // 1 : 不存在  
             if ((set[index] & (1 << bit)) != 0) { // 说明这个 bit位 是 1, 不存在, 要将其修改为 0.
                zeros--;    // 注意, 我们这里是判断不存在的数量, 我们执行的操作是添加, 所以--.  
                ones++;     // 同样的, 我们这里执行的是添加操作, 所以要++.  
                set[index] ^= (1 << bit); // 我们前面已经有了判断, 这个 bit位 是 1, 所以要将其反转.  
             }  
          }  
       }  
  
       // 把i这个数字从位图中移除  
       public void unfix(int i) {  
          int index = i / 32;  
          int bit = i % 32;  
          if (!reverse) {  // 没有经历过反转.  
             if ((set[index] & (1 << bit)) != 0) {  
                ones--;  // 存在的-- 因为执行的是删除操作  
                zeros++; // 不存在的++, 因为执行的是删除操作.  
                set[index] ^= (1 << bit);  
             }  
          } else {         // 经历过反转.  
             if ((set[index] & (1 << bit)) == 0) {  
                ones--;   // 存在的-- 因为执行的是删除操作  
                zeros++;  // 不存在的++, 因为执行的是删除操作.  
                set[index] |= (1 << bit);  
             }  
          }  
       }  
  
       public void flip() {  
          reverse = !reverse;  // 直接进行反转, 省去了整个位图的遍历, 毕竟 reverse 不是 true 就是 false.          
          int tmp = zeros;  
          zeros = ones;  // 这里还需要交换 0 与 1 的值.(计数)的情况.  
          ones = tmp;  
       }  
  
       public boolean all() {  
          return ones == size; // 直接判断 1 的数量是不是等于 size.       
        }  
  
       public boolean one() {  
          return ones > 0; // 只要确定有一个位置上有 1 就行了,  
       }  
  
       public int count() {  
          return ones;    // 判断存在中的数字有几个, 直接返回 1 的个数.  
       }  
  
  
       // 这个方法就是将数组中所有的 bit位上的1 都拼起来, 拿出来一个下标为 0, 1, 2, 3 ... n 就开始拼就行.  
       public String toString() {  
          StringBuilder builder = new StringBuilder();  
          for (int i = 0, k = 0, number, status; i < size; k++) { // k 表示拿到了第一个整数.  
             number = set[k];  
             for (int j = 0; j < 32 && i < size; j++, i++) {  
                status = (number >> j) & 1;  // 将每一个状态都进行判断.  
                status ^= reverse ? 1 : 0;  // 需要判断 reverse 是 true 还是 false. 若是true, 需要统计 0, 若是 false 直接统计 1.                
                builder.append(status);  
             }  
          }  
          return builder.toString();  
       }  
    }  
  
}

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

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

相关文章

SpringBoot项目:前后端打包与部署(使用 Maven)

文章目录 IDEA后端打包与部署&#xff08;使用 Maven&#xff09;1. 确保 Maven 已安装&#xff0c;并引入 pom 插件2. 清理并安装项目3. 定位生成的 JAR 包和配置文件4. 创建部署文件夹5. 上传到服务器 前端打包与部署&#xff08;使用 npm&#xff09;1. 确保 Node.js 和 npm…

Oracle 数据库安装和配置详解

Oracle 数据库安装和配置详解 Oracle 数据库是一款功能强大、广泛使用的企业级关系数据库管理系统 (RDBMS)&#xff0c;适用于处理大型数据库和复杂事务。本文将介绍如何在 Linux 和 Windows 环境下安装 Oracle 数据库&#xff0c;并对其进行基本配置&#xff0c;帮助开发者快…

深入理解MySQL InnoDB中的B+索引机制

目录 一、InnoDB中的B 树索引介绍 二、聚簇索引 &#xff08;一&#xff09;使用记录主键值的大小进行排序 页内记录排序 页之间的排序 目录项页的排序 &#xff08;二&#xff09;叶子节点存储完整的用户记录 数据即索引 自动创建 &#xff08;三&#xff09;聚簇索引…

[ 蓝桥 ·算法双周赛 ] 第 19 场 小白入门赛

&#x1f525;博客介绍&#xff1a; EvLast &#x1f3a5;系列专栏&#xff1a; <<数据结构与算法>> << 算法入门>> << C项目>> &#x1f3a5; 当前专栏: << 算法入门>> 专题 : 帮助小白快速入门算法竞赛 &#x1f44d…

机器学习西瓜书笔记(十四) 第十四章概率图模型

第十四章 概率图模型14.1 隐马尔可夫模型14.1.1 小结 14.2 马尔可夫随机场小结 14.3 条件随机场14.3.1 小结 14.4 学习与推断14.4.1 变量消去14.4.2 信念传播小结 14.5 近似推断14.5.1 MCMC采样14.5.2 变分推断小结 14.6 话题模型14.6.1 小结 总结 概率图模型 14.1 隐马尔可夫…

31 基于51单片机的水位监测系统仿真

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;DHT11温湿度检测&#xff0c;水位检测&#xff0c;通过LCD1602显示&#xff0c;超过阈值报警&#xff0c;继电器驱动电机转动。通过矩阵按键切换选择设置各项参数阈值。 …

LabVIEW程序怎么解决 Bug?

在LabVIEW开发过程中&#xff0c;发现和解决程序中的Bug是确保系统稳定运行的关键环节。由于LabVIEW采用图形化编程方式&#xff0c;Bug的排查和处理与传统编程语言略有不同。以下是解决LabVIEW程序中Bug的常见方法和技巧&#xff0c;涵盖从问题发现到解决的多个步骤和角度&…

vue3学习:axios输入城市名称查询该城市天气

说来惭愧&#xff0c;接触前端也有很长一段时间了&#xff0c;最近才学习axios与后端的交互。今天学习了一个查询城市天气的案例&#xff0c;只需输入城市名称&#xff0c;点击“查询”按钮便可以进行查询。运行效果如下&#xff1a; 案例只实现了基本的查询功能&#xff0c;没…

中断系统的原理

一、介绍 中断是为使单片机具有对外部或内部随机发生的事件实时处理而设置的。中断是指‌CPU在正常运行程序时&#xff0c;由于内部或外部事件的发生&#xff0c;导致CPU中断当前运行的程序&#xff0c;转而去执行其他程序的过程。‌ 中断可以是硬件产生的&#xff0c;也可以是…

【重学 MySQL】四十八、DCL 中的 commit 和 rollback

【重学 MySQL】四十八、DCL 中的 commit 和 rollback commit的定义与作用rollback的定义与作用使用场景相关示例注意事项DDL 和 DML 的说明 在MySQL中&#xff0c;DCL&#xff08;Data Control Language&#xff0c;数据控制语言&#xff09;用于管理数据库用户和控制数据的访问…

集师专属知识付费小程序搭建 心理咨询小程序搭建

一、产品简介 集师SaaS知识付费软件&#xff0c;为知识创业者或商家提供一站式内容交付解决方案&#xff0c;助力商家搭建集品牌传播、商业变现和用户运营于一体的线上知识服务系统&#xff0c;覆盖全渠道经营场景&#xff0c;占据每个流量入口&#xff0c;使流量变现快速高效…

集智书童 | 用于时态动作检测的预测反馈 DETR !

本文来源公众号“集智书童”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;用于时态动作检测的预测反馈 DETR ! 视频中的时间动作检测&#xff08;TAD&#xff09;是现实世界中的一个基本且具有挑战性的任务。得益于 Transformer …

什么是 HTTP Get + Preflight 请求

当在 Chrome 开发者工具的 Network 面板中看到 GET Preflight 的 HTTP 请求方法时&#xff0c;意味着该请求涉及跨域资源共享 (CORS)&#xff0c;并且该请求被预检了。理解这种请求的背景&#xff0c;主要在于 CORS 的工作机制和现代浏览器对安全性的管理。 下面是在 Chrome …

Linux: network: 典型网络延迟图,CPU导致;

接上回说&#xff0c;https://mzhan017.blog.csdn.net/article/details/142689870&#xff1b; 其中在debug的过程中&#xff0c;看到下面这个IO图&#xff0c;这个图比较经典&#xff0c;是一个典型的网络延迟图&#xff0c;可用作为分析问题的一个参考。 如下图&#xff1a;黑…

2024年10月HarmonyOS应用开发者高级认证全新题库

注意事项&#xff1a;切记在考试之外的设备上打开题库进行搜索&#xff0c;防止切屏三次考试自动结束&#xff0c;题目是乱序&#xff0c;每次考试&#xff0c;选项的顺序都不同 新版题库&#xff1a;单选题40题 多选题20题 注意选项答案顺序不一样&#xff0c;大家记得看选项…

Redis篇(缓存机制 - 基本介绍)(持续更新迭代)

目录 一、缓存介绍 二、经典三缓存问题 1. 缓存穿透 1.1. 简介 1.2. 解决方案 1.3. 总结 2. 缓存雪崩 2.1. 简介 2.2. 解决方案 2.3. 总结 3. 缓存击穿 3.1. 简介 3.2. 解决方案 3.3. 总结 4. 经典三缓存问题出现的根本原因 三、常见双缓存方案 1. 缓存预热 1…

第Y2周:训练自己的数据集

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 在上一次体验yolov5s的为基础上&#xff0c;这次将训练自己的数据集。 在YOLO目标检测算法中常用的三种标签格式&#xff1a;voc(xml)、coco(json)和yolo(txt…

安防监控/视频系统EasyCVR视频汇聚平台如何过滤134段的告警通道?

视频汇聚/集中存储EasyCVR安防监控视频系统采用先进的网络传输技术&#xff0c;支持高清视频的接入和传输&#xff0c;能够满足大规模、高并发的远程监控需求。平台支持国标GB/T 28181协议、部标JT808、GA/T 1400协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为…

LabVIEW提高开发效率技巧----严格类型化定义

在LabVIEW开发过程中&#xff0c;严格类型化定义&#xff08;Strict Typedefs&#xff09; 是一种工具&#xff0c;用于保证程序中控件和常量的一致性&#xff0c;减少错误&#xff0c;提高维护效率。通过使用严格类型化定义&#xff0c;开发者可以确保在程序的多个地方引用相同…

个人项目简单https服务配置

1.SSL简介 SSL证书是一种数字证书&#xff0c;由受信任的证书颁发机构&#xff08;CA&#xff09;颁发&#xff0c;用于在互联网通信中建立加密链接。SSL代表“安全套接层”&#xff0c;是用于在互联网上创建加密链接的协议。SSL证书的主要目的是确保数据传输的安全性和隐私性…