【Java】位图 布隆过滤器

news2025/2/5 7:20:17

位图

初识位图

位图, 实际上就是将二进制位作为哈希表的一个个哈希桶的数据结构, 由于二进制位只能表示 0 和 1, 因此通常用于表示数据是否存在.

如下图所示, 这个位图就用于标识 0 ~ 14 中有什么数字存在

在这里插入图片描述

可以看到, 我们这里相当于是把下标作为了 key-value 的一员. 但是这样同样也使得位图这个数据结构非常有局限性, 因为下标只能是整数. 因此通常来说, 位图都是用于存储整数是否存在的.

那么位图这么有局限性, 我们为何要使用它呢?

实际上, 我们可以看到, 存储一个数字是否存在, 我们只需要消耗 1 个比特位, 而如果我们使用正常的一个哈希表的键值对来存储的话, 首先是一个整型就是 4 个字节, 其次就是一个 boolean 类型, 我们暂定为 1 字节大小. 而这样相当于就占了 5 个字节, 总共为 40 个比特位.

那么结论也很明显了, 位图存储一个数据是否存在, 只需要消耗 1 比特空间, 相较于直接使用哈希表键值对存储, 大大提升了空间的使用效率.

实现思路

首先要实现位图, 我们肯定需要一个能很好操作比特位的数据类型, 那么在这一点上, 只要是整型都可以轻易的做到, 因此 byte, short, int, long 都是可行的

但是如果只使用单个数, 那肯定是不够的, 以 int 为例, 单个 int 就只有 32 位, 那假如说要存 100 个数字呢? 因此这里最好我们使用一个数组来操作. 我们这里就采用 byte 数组来实现(因为画图好画)

那么由于 byte 是 8 位, 因此我们就可以知道 byte[0] (这里没有数组名因此这样简称) 对应着的是前 8 位, 代表着 0 ~ 7 这八个数字. 而 byte[1] 则往后对应, 对应着 8 ~ 15, 后续同理… 后续我们通过使用 num / 8 就可以轻松的获取到对应下标

在这里插入图片描述

但是接下来另一个问题来了, 我们如何操作到位图中的每一个位呢? 如果是最简单的思路, 其实就是靠数字 1 来操作, 因为数字 1 的二进制位为 0000 0001 其中这个单独的 1 位置可以非常便于我们操作, 并且相较于其他的数字可读性非常的高.

那么此时我们会发现一个问题, 假如我想要令 byte[0] 中代表 0 的一位为 1, 那么此时我们还需要通过左移 1 来实现, 如下图所示

在这里插入图片描述

这样有没有问题呢? 当然没有, 不过依旧是比较的反直觉, 明明我们修改的数应该是 0 但是却反而需要通过移位来做, 因此我们这里就采用在每一个数字里面里面, 下标都是逆序的设计方式

在这里插入图片描述

可以看到此时在 byte[0] 里面, 下标就是从 7 依次减到 0, 而在 byte[1] 里面, 下标从 15 减到 8. 随后如果我们要修改 0 对应的数字, 需要左移的位就是 0 % 8, 其他的同理

当然, 这部分的设计是完全偏向于个人喜好的, 如果想要实现刚开始的顺序记录, 也不是不可以. 不过此处后续将会采用内部下标逆序的设计方式来书写代码, 感兴趣的可以自行实现顺序的版本.

位的基本操作

由于要操作位图, 相关的位操作我们必须要提前了解下, 这样才会便于我们后续代码的书写. 当然这里介绍的是具体的位相关操作, 如果对二进制位没有基本了解以及位运算也没有基本了解的, 需要自行先去了解一下相关内容

前提要求, 下面的所有第 x 位指的是从右往左, 从 0 开始来计数的

例如 0000 0001

其中 1 在第 0 位

  1. 给定一个数 n, 确定它的二进制中第 x 位是 0 还是 1

这个其实非常简单, 直接用一个 1 按位与即可, 要么把 1 左移 x 位后按位与, 要么把 n 右移 x 位后按位与

(1 << x) & n == 1 或 (n >> x) & n == 1

这个操作主要用于位图的查找功能


  1. 将一个数 n 的二进制中的第 x 位修改为 1

要把第 x 位修改为 1, 使用一个 1 左移 x 位后, 采用按位或操作即可

n |= (1 << x)

这个操作主要用于位图的记录功能


  1. 将一个数 n 的二进制中的第 x 位修改为 0

这个要修改为 0, 其实还是要用 1 左移 x 位, 不过要再取一次反, 然后采用按位与的操作

n &= (~(1 << x))

这个操作主要用于位图的删除功能

位图实现

其实目前所有的基础知识都介绍完了, 尤其是上面的三个基础操作, 接下来实现代码应该是非常简单的

初始化

public class MyBitSet {
    private byte[] bits;

    private static final int DEFAULT_SIZE = 8;

    public MyBitSet() {
        this(DEFAULT_SIZE);
    }
    public MyBitSet(int size) {
        bits = new byte[size / 8 + 1];
    }
}

存储元素

// 将某个数存入位图
public void set(int index) {
    int byteIndex = index / 8;
    // 扩容
    if(byteIndex >= bits.length){
        bits = Arrays.copyOf(bits, byteIndex + 1);
    }
    int bitIndex = index % 8;

    bits[byteIndex] |= (byte) (1 << bitIndex);
}

查找元素

// 查看某个数在位图中是否存在
public boolean get(int index) {
    int byteIndex = index / 8;
    int bitIndex = index % 8;
    return (bits[byteIndex] & (1 << bitIndex)) != 0;
}

删除元素

// 将某个数从位图中清除
public void clear(int index) {
    int byteIndex = index / 8;
    int bitIndex = index % 8;
    bits[byteIndex] &= (byte) ~(1 << bitIndex);
}

位图应用

位图由于其只能存储整数以及占用空间小的特性, 通常可以用于在海量的整数中去记录一个数是否存在, 另外其还可以用于做去重 + 排序的工作

public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 5, 4, 7, 8, 9, 4, 22, 3, 1};
        MyBitSet bitSet = new MyBitSet(100);
        // 添加元素
        for (int i : arr) {
            bitSet.set(i);
        }
        // 遍历
        for (int i = 0; i < 100; i++) {
            if (bitSet.get(i)) {
                System.out.print(i + " ");
            }
        }
    }
}

同时它也可以实现一些基本的集合功能, 例如求交集

public BitSet and(MyBitSet other) {
    // 获取两个 BitSet 中较大的长度
    int size = Math.max(bits.length, other.bits.length) * 8;
    // 创建一个 BitSet 来存储结果
    BitSet result = new BitSet(size);
    for (int i = 0; i < size; i++) {
        // 如果两个 BitSet 的对应位置都为 1,则将结果 BitSet 的对应位置设为 1
        if (get(i) && other.get(i)) {
            result.set(i);
        }
    }
    return result;
}

测试代码

public class Main {
    public static void main(String[] args) {
        int[] set1 = {1, 5, 4, 7, 8, 9, 4, 22, 3, 1};
        int[] set2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        MyBitSet bitSet1 = new MyBitSet(100);
        MyBitSet bitSet2 = new MyBitSet(100);
        for (int i = 0; i < set1.length; i++) {
            bitSet1.set(set1[i]);
        }
        for (int i = 0; i < set2.length; i++) {
            bitSet2.set(set2[i]);
        }
        BitSet and = bitSet1.and(bitSet2);
        for (int i = 0; i < 100; i++) {
            if(and.get(i)){
                System.out.print(i + " ");
            }
        }
    }
}

BitSet 使用

Java 也提供了位图相关实现, 即 BitSet. 使用非常简单, 使用 get(), set() 方法即可

public class Main {
    public static void main(String[] args) {
        BitSet bitSet = new BitSet(8);
        int[] arr1 = {1, 2, 4, 5, 22, 6, 9, 4};
        for (int i = 0; i < arr1.length; i++) {
            bitSet.set(arr1[i]);
        }
        System.out.println(bitSet);
    }
}

布隆过滤器

初识布隆过滤器

前面我们提到如果面对着海量数据, 哈希表就会过度占用空间, 位图则只能用于处理整型. 那么有没有什么办法可以即节省空间, 又能处理海量数据呢?

此时有人可能就想了, 那为何我们不能把一个东西进行哈希, 计算出哈希值后放到对应的位图里面呢?

但是这种做法忽略了哈希表的一个重要特点, 就是会发生哈希冲突, 倘若发生哈希冲突, 那么此时位图是很难进行处理的.

其实布隆过滤器, 就相当于是我们上面这个思路的拓展, 它对一个元素, 会采用多个不同的哈希函数来进行哈希, 最后将位图中的多个位进行记录.

那此时可能有人还是要问了: 这个似乎也没有完全解决冲突问题, 那这个思路岂不是还有问题?

实际上, 布隆过滤器本身设计出来就是作为一个概率型数据结构存在的, 在判断某一个元素是否存在于容器中的时候, 会存在一定的误判率. 不过这个是可以通过调整哈希函数的个数以及容器的大小来调整误判概率的. 具体如何计算是一个数学问题, 我们这里就不多讨论了.

误判相关

实际上, 布隆过滤器的原理还是非常简单的, 无非就是用多个哈希函数去计算出下标然后丢到位图里面. 但是我们仍旧没有弄明白, 为何布隆过滤器会有误判, 误判会导致什么结果?

实际上, 为什么会有误判这个点非常好理解, 其实就是位图没法处理哈希冲突的一种体现. 我们以极端情况来看, 假设只使用一个哈希函数, 对 zhangsan 这个名字进行哈希, 得到的下标是 10, 我们将其存储到位图中.

在这里插入图片描述

随后我们尝试在里面查找 lisi 这个数据, 但是假设其计算的哈希下标也是 10, 那么此时访问 10 发现结果是 1, 就发生误判了

在这里插入图片描述

针对多个哈希函数, 其实也是同样的道理, 无非就是访问的点多了, 概率会更低而已.

那么现在我们已知了, 布隆过滤器返回 true 的时候, 是有可能误判的, 那么当其返回 false 的时候有没有可能会误判呢?

其实是不会的, 因为返回 true 会误判的本质是, 那个位置发生了哈希冲突, 且有某一个元素占用了那个位置, 那么只要有元素占用了那个位置, 就一定会返回 true. 而返回 false 则不满足有元素占用的那个条件, 因此返回 false 是不会发生误判的.

综上所述, 布隆过滤器会在返回 true 的时候概率发生误判, 而 false 则一定不会发生误判.

布隆过滤器实现

初始化

public class MyBloomFilter {
    // 位图
    private BitSet bitSet;
    // 标记当前容量, 主要用于给哈希 -> 下标的映射
    private int size;
    // 采用 HashMap 类似设计, 便于进行哈希 -> 下标的映射
    private static final int DEFAULT_SIZE = 1 << 25;
    // 随机种子, 用于实现不同的哈希函数, 这里是随便写的
    private static final int[] seeds = new int[]{5, 7, 11, 13};
    // 哈希函数及其实现
    private MyHash[] func;
    static class MyHash {
        int seed;
        public MyHash(int seed) {
            this.seed = seed;
        }
        public int hash(Object key) {
            int h;
            // 直接使用 key.hashCode() * seed 来实现简单的哈希随机函数
            return (key == null) ? 0 : (h = key.hashCode() * seed) ^ (h >>> 16);
        }
    }

    public MyBloomFilter() {
        bitSet = new BitSet(DEFAULT_SIZE);
        func = new MyHash[seeds.length];
        size = DEFAULT_SIZE;
        for (int i = 0; i < seeds.length; i++) {
            func[i] = new MyHash(seeds[i]);
        }
    }
}

增加和查找

非常简单的两个方法, 无非就是多次调用哈希函数并且计算下标, 最后存储/读取位图而已

public void add(Object key) {
    if (key == null) return;
    for (MyHash f : func) {
        bitSet.set(f.hash(key) & (size - 1));
    }
}

public boolean contains(Object key) {
    if (key == null) return false;
    for (MyHash f : func) {
        if(!bitSet.get(f.hash(key) & (size - 1))) return false;
    }
    return true;
}

优缺点

优点:

  1. 添加和查询的时间复杂度低, 具体时间复杂度与哈希函数有关
  2. 不存储元素本身, 需要保密的场景下有一些优势
  3. 允许有误判率的情况下, 时间和空间效率都很高
  4. 使用相同哈希函数计算的布隆过滤器可以支持集合运算

缺点:

  1. 存在误判率(可以通过添加白名单来进行兜底, 对可能进行误判的数据进行存储)
  2. 传统的布隆过滤器不支持删除操作, 因为可能会影响其他元素. 如果需要实现可以给每一个位加一个计数器, 不过数据量过多的情况可能会导致计数器发生溢出
  3. 不能获取到元素本身

使用场景

  1. 去重场景, 例如网页爬虫去重 URL, 分布式系统日志去重等
  2. 过滤场景, 记录并且过滤垃圾邮件
  3. 解决缓存击穿问题:
    1. 背景: 系统访问缓存时, 如果发现缓存中没有相应数据, 那么就会尝试请求数据库来查找数据. 那么此时攻击者可以借助这个特性, 大量仿造不存在的数据对数据库进行攻击, 使得数据库服务器崩溃.
    2. 解决方案: 使用布隆过滤器记录下数据库中的所有数据, 经过缓存前先进行一轮判断, 发现返回 false 直接不响应即可(因为布隆过滤器返回 false 一定代表不存在). 若返回 true, 则才允许尝试访问后续的其他资源.

使用布隆过滤器

虽然 Java 没有提供官方的布隆过滤器实现, 但是第三方库还是有一些实现的, 下面我们简单使用一个

首先使用 Maven 创建项目, 并且引入下面的依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>19.0</version>
</dependency>

然后可以通过下面的代码创建一个布隆过滤器, 其中第一个参数主要是将对象转为字节数组, 提供给布隆过滤器用于进行哈希运算的, 由于我们这里只是简单使用, 因此不详细介绍了

public class Main {

    public static void main(String[] args) {
        // 期望的误判率
        double fpp = 0.001;
        // 预计要插入多少数据
        int size = 100000;
        // 创建布隆过滤器
        BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);

    }
}

接下来我们来简单测试下这个东西的误判率

public class Main {

    public static void main(String[] args) {
        // 期望的误判率
        double fpp = 0.001;
        // 预计要插入多少数据
        int size = 100000;
        // 创建布隆过滤器
        BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);

        // 存 0 ~ 100000
        for (int i = 0; i <= size; i++) {
            bloomFilter.put(i);
        }

        // 通过 100000 ~ 200000 的数据,看看有多少个是误判的
        int count = 0;
        for (int i = 100000; i <= 200000; i++){
            if (bloomFilter.mightContain(i)) {
                count++;
            }
        }

        System.out.println("误判率:" + count + " / " + (200000 - 100000) + " = " + (double) count / (200000 - 100000));

    }
}

运行可以发现误判率基本大差不差, 是符合预期的

在这里插入图片描述

海量数据处理相关问题

  1. 给一个超过 100G 大小的日志文件, 文件中存储着 IP 地址, 如何找到出现次数最多 / Top-K 的 IP 地址?

这种问题, 说是几百 G 的数据, 本质上是希望告诉你, 这个数据是无法存储到内存中的, 也就是说把这些数据直接存储到内存中是不可行的, 我们需要进行预处理.

那么针对这种大文件的处理, 核心思路无非就一个, 拆小文件, 但是这里也有两种拆法:

  1. 无脑拆分, 直接拆成能够装入内存中的大小, 随后遍历每一个文件进行全局计数.
  2. 哈希拆分, 通过对 IP 地址进行哈希操作, 保证每一个 IP 地址都能够被映射到同一个文件中. 最后分别统计出每一个文件出现次数最多的即可, 就不需要全局计数了. (假如是 Top-k 问题, 则需要对应选出每个文件 Top-k 的 IP 数, 随后进行下比较即可)

当然, 这里的哈希拆分我们需要注意, 哈希函数必须要合理, 使得每一个文件大小是均匀的, 否则可能会导致某一个文件过大无法放入内存进行处理.

  1. 给定两个文件, 分别有 100 亿个整数, 如何求其的交集, 并集, 差集?
  • 哈希拆分: 依旧是老套路, 通过哈希把相同数字塞同一个文件里面, 随后对每一个小文件进行对应集合操作
  • 位图:
    • 使用两个位图来记录数据
    • 将两个位图中的所有位进行与操作, 得到交集
    • 将两个位图中的所有位进行或操作, 得到并集
    • 将两个位图中的所有位进行异或操作, 得到差集
  1. 给定 100 亿个整数, 设计算法找出只出现过一次的整数
  • 哈希拆分思路: 依旧是通过哈希来把相同数字放到同一个文件中, 随后查看每一个小文件即可. 同样的, 这里也需要保证哈希函数设计合理, 使得每一个文件大小均匀. 这也是为什么不能采用区间划分, 因为可能某一些数字出现很多, 从而导致数字集中在一个文件里面
  • 双位图思路:

位图, 是可以用于处理海量整数数据的记录的, 但是问题就在于它只能记录一个数是否出现, 即只能表示有和无这两个信息. 而如今这个情景需要我们记录三个信息: 1. 无 2. 有一次 3. 有一次以上

那么有没有什么办法可以让位图可以多记录一些信息呢? 当然有, 一个位图不够, 那么就用两个.

此时相当于一个数对应着两个位, 此时可以表示的情况就有 00 01 10 11 四种情况了, 用于记录三种情况绰绰有余. 并且其实这两个位可以用于做二进制计数, 分别对应 0 1 2 3

  • 单位图思路:

那么继承上面的双位图思路, 我们能否使用单个位图呢? 答案当然也是可以的, 但是一个位还是不够用, 因此我们可以给每一个数字分两个位, 随后记录方式和上面一样.

  1. 给定 100 亿个整数, 设计算法找出出现次数不超过两次的整数

这个问题实际上是上面问题的拓展, 但是核心思路都是一致的

  • 哈希拆分思路: 依旧是通过哈希来把相同数字放到同一个文件中, 随后查看每一个小文件即可.
  • 位图思路: 采用两个位图/单位图的两个位, 来进行二进制计数, 记录出现次数为 01 和 10 的即可(即对应出现次数为 1 和 2 的)
  1. 给两个 100G 文件, 如何近似的求其交集?

这里由于并不要求我们精准的求出交集, 所以我们除了采用经典的哈希拆分思路还可以借助布隆过滤器来做.

思路也非常的简单, 首先把第一个文件里面的数据丢到布隆过滤器中, 随后遍历第二个文件来在布隆过滤器中查找是否存在即可.

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

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

相关文章

【自然语言处理(NLP)】生成词向量:GloVe(Global Vectors for Word Representation)原理及应用

文章目录 介绍GloVe 介绍核心思想共现矩阵1. 共现矩阵的定义2. 共现概率矩阵的定义3. 共现概率矩阵的意义4. 共现概率矩阵的构建步骤5. 共现概率矩阵的应用6. 示例7. 优缺点优点缺点 **总结** 目标函数训练过程使用预训练的GloVe词向量 优点应用总结 个人主页&#xff1a;道友老…

如何获取sql数据中时间的月份、年份(类型为date)

可用自带的函数month来实现 如&#xff1a; 创建表及插入数据&#xff1a; create table test (id int,begindate datetime) insert into test values (1,2015-01-01) insert into test values (2,2015-02-01) 执行sql语句,获取月份&#xff1a; select MONTH(begindate)…

NSSCTF Pwn [NISACTF 2022]ezpie 题解

下载 exeinfo checksec 32位 NX PIE开启 查看main函数&#xff1a; 后门函数&#xff1a; 发现已经给出了main函数地址 因为开启了PIE 所以IDA中 后门函数减去main函数的后三位就是偏移 给出的函数加上这个数就是后门函数地址 exp&#xff1a; from pwn import *p remote(…

【01】共识机制

BTF共识 拜占庭将军问题 拜占庭将军问题是一个共识问题 起源 Leslie Lamport在论文《The Byzantine Generals Problem》提出拜占庭将军问题。 核心描述 军中可能有叛徒&#xff0c;却要保证进攻一致&#xff0c;由此引申到计算领域&#xff0c;发展成了一种容错理论。随着…

文字加持:让 OpenCV 轻松在图像中插上文字

前言 在很多图像处理任务中,我们不仅需要提取图像信息,还希望在图像上加上一些文字,或是标注,或是动态展示。正如在一幅画上添加一个标语,或者在一个视频上加上动态字幕,cv2.putText 就是这个“文字魔术师”,它能让我们的图像从“沉默寡言”变得生动有趣。 今天,我们…

【R语言】环境空间

一、环境空间的特点 环境空间是一种特殊类型的变量&#xff0c;它可以像其它变量一样被分配和操作&#xff0c;还可以以参数的形式传递给函数。 R语言中环境空间具有如下3个特点&#xff1a; 1、对象名称唯一性 此特点指的是在不同的环境空间中可以有同名的变量出现&#x…

惰性函数【Ⅱ】《事件绑定的自我修养:从青铜到王者的进化之路》

【Ⅱ】《事件绑定的自我修养&#xff1a;从青铜到王者的进化之路》 1. 代码功能大白话&#xff08;给室友讲明白版&#xff09; // 青铜写法&#xff1a;每次都要问浏览器"你行不行&#xff1f;" function addEvent青铜版(element, type, handler) {if (window.add…

Vue3的el-table-column下拉输入实时查询API数据选择的实现方法

由于本人对el-table-column有下拉输入选择的要求&#xff0c;根据网上搜索的资料及本人优化&#xff0c;推出我比较满意的方法&#xff0c;供各位读者参考使用。 效果图 el-table-column写法 <el-table-columnlabel"货品编号"align"center"prop"…

[mmdetection]fast-rcnn模型训练自己的数据集的详细教程

本篇博客是由本人亲自调试成功后的学习笔记。使用了mmdetection项目包进行fast-rcnn模型的训练&#xff0c;数据集是自制图像数据。废话不多说&#xff0c;下面进入训练步骤教程。 注&#xff1a;本人使用linux服务器进行展示&#xff0c;Windows环境大差不差。另外&#xff0…

RFID涉密载体管控系统|支持国产化、自主研发

涉密载体管理系统DW-S402是一套成熟系统&#xff0c;是用于对各种涉密载体进行有效管理&#xff0c;实现对载体的智能化、规范化、标准化管理&#xff0c;广泛应用于保密、机要单位以及企事业单位等有载体保管需求的行业。 用户为对文件资料、存储介质等管理严格的单位&#x…

BUU14 [极客大挑战 2019]PHP1

用dirsearch扫描文件&#xff0c;扫了一万年什么也没扫出来 从网上看的wp&#xff0c;他们扫出来www.zip 这里直接用上了&#xff0c;以后有空再扫一遍 下载www.zip 在index.php中 说明要输入select 打开class.php <?php include flag.php;error_reporting(0);class…

数据分析师使用Kutools for Excel 插件

数据分析师使用Kutools for Excel 插件 Kutools for Excel 是一款功能强大的 Excel 插件&#xff0c;旨在提高 Excel 用户的工作效率&#xff0c;简化复杂的操作。它提供了超过 300 个增强功能&#xff0c;帮助用户快速完成数据管理、格式化、排序、分析等任务&#xff0c;特别…

【高级篇 / IPv6】(7.2) ❀ 04. 在60E上配置ADSL拨号宽带上网(IPv4) ❀ FortiGate 防火墙

【简介】除了单位用户以外&#xff0c;大部分个人用户目前使用的仍然是30E、50E、60E系列防火墙&#xff0c;固件无法达到目前最高版本7.6&#xff0c;这里以最常用的60E为例&#xff0c;演示固件版本7.2下实现ADSL拨号宽带的IPv6上网。由于内容比较多&#xff0c;文章分上、下…

基于LMS算法的自适应滤波器设计与MATLAB实现

1. 引言 自适应滤波器是信号处理领域的重要工具&#xff0c;能够根据输入信号的统计特性自动调整滤波器参数。其中&#xff0c;最小均方&#xff08;LMS&#xff09;算法因其计算简单、易于实现的特点&#xff0c;成为最常用的自适应滤波算法之一&#xff0c;广泛应用于噪声消…

【现代深度学习技术】深度学习计算 | 延后初始化自定义层

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上&#xff0c;结合当代大数据和大算力的发展而发展出来的。深度学习最重…

Java导出Excel简单工具类

一、maven配置 <!--jxl--><dependency><groupId>net.sourceforge.jexcelapi</groupId><artifactId>jxl</artifactId><version>2.6.12</version></dependency>二、工具类方法 package util2;import jxl.Workbook; impor…

蓝桥与力扣刷题(141 环形链表)

题目&#xff1a;给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的…

【小鱼闪闪】做一个物联网控制小灯的制作流程简要介绍(图文)

1、注册物联网云平台&#xff0c;这里选用巴法云 2.、新建主题 “ledtest” 3、 使用Arduino或Mixly软件编写单片机程序&#xff08;需要引用巴法云库文件&#xff09;&#xff0c;程序中订阅“ledtest”主题&#xff0c;用于接收单片机发送来的数据。此处会将连接的温度传感器…

图论常见算法

图论常见算法 算法prim算法Dijkstra算法 用途最小生成树&#xff08;MST&#xff09;&#xff1a;最短路径&#xff1a;拓扑排序&#xff1a;关键路径&#xff1a; 算法用途适用条件时间复杂度Kruskal最小生成树无向图&#xff08;稀疏图&#xff09;O(E log E)Prim最小生成树无…

BUU16 [ACTF2020 新生赛]BackupFile1

扫到index.php.bak 实在扫不出来可以试试一些常有的文件&#xff0c;比如flag.php&#xff08;flag.php.bak&#xff09;&#xff0c;index.php&#xff08;index.php.bak&#xff09; <?php include_once "flag.php";if(isset($_GET[key])) {$key $_GET[key…