C# 位图算法

比如大量整数的快速查找,利用位操作来表示整数集合,因此操作速度非常快。

普通查找算法

首先,我们看看普通的查找算法,比如使用List<int>HashSet<int>来查找整数。

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        List<int> numbers = new List<int>();
        Random random = new Random();
        for (int i = 0; i < 1000000; i++)
        {
            numbers.Add(random.Next(0, 1000000));
        }

        // 查找数字
        int target = 500000;
        bool exists = numbers.Contains(target);
        Console.WriteLine("普通算法 - 目标存在: " + exists);
    }
}

位图算法

使用位图算法实现同样的查找。假设整数的范围在0999999之间,我们可以使用一个位图来表示这些整数

using System;

public class Program
{
    public static void Main()
    {
        const int size = 1000000;
        byte[] bitmap = new byte[size / 8]; // 使用位图存储数据
        Random random = new Random();

        // 填充位图
        for (int i = 0; i < size; i++)
        {
            int num = random.Next(0, size);
            SetBit(bitmap, num);
        }

        // 查找数字
        int target = 500000;
        bool exists = GetBit(bitmap, target);
        Console.WriteLine("位图算法 - 目标存在: " + exists);
    }

    private static void SetBit(byte[] bitmap, int num)
    {
        bitmap[num / 8] |= (byte)(1 << (num % 8));
    }

    private static bool GetBit(byte[] bitmap, int num)
    {
        return (bitmap[num / 8] & (1 << (num % 8))) != 0;
    }
}

如果没看懂,这里是SetBitGetBit 的实现细节

private static void SetBit(byte[] bitmap, int num)
{
    // 计算该数字应在 bitmap 数组中的哪个字节
    int byteIndex = num / 8;

    // 计算该数字在该字节中的哪个位(0-7)
    int bitIndex = num % 8;

    // 使用位运算将该位设置为1
    bitmap[byteIndex] |= (byte)(1 << bitIndex);
}

private static bool GetBit(byte[] bitmap, int num)
{
    // 计算该数字应在 bitmap 数组中的哪个字节
    int byteIndex = num / 8;

    // 计算该数字在该字节中的哪个位(0-7)
    int bitIndex = num % 8;

    // 检查该位是否为1
    return (bitmap[byteIndex] & (1 << bitIndex)) != 0;
}

假设我们要在位图中设置并检查数字13的存在性:

  1. 设置数字13的存在性:

    • byteIndex = 13 / 8 = 1 (数字13位于第1个字节)
    • bitIndex = 13 % 8 = 5 (数字13在第1个字节的第5位)
    • 1 << 5 结果是00100000,所以bitmap[1] |= 00100000会将第1个字节的第5位设置为1。
  2. 检查数字13是否存在:

    • 同样计算byteIndexbitIndex
    • 通过bitmap[1] & 00100000检查第5位是否为1,如果是1,说明数字13存在,返回true

性能对比与优势说明

  • 普通查找算法:

    • 优点: 实现简单,适用于查找少量数据或范围较大的数据。
    • 缺点 : 随着数据量增加,List<int>的查找复杂度为O(n),而HashSet<int>的查找复杂度为O(1),但它们都存在一定的内存和时间开销,特别是在处理非常大量数据时,性能会下降。
  • 位图算法:

    • 优点: 在整数范围已知且较小的情况下,查找、插入和删除操作的时间复杂度为O(1),非常高效。因为它直接通过位操作确定数据的存在性,内存占用也非常少。
    • 缺点: 位图算法仅适用于整数范围已知且范围相对较小的情况。如果整数范围很大,位图的大小会显著增加。

性能测试

假设我们在一个范围为0999999之间的整数集合中查找一个数字500000

  • 普通查找算法 :当使用List<int>时,查找的平均时间复杂度为O(n),对于大规模数据,性能较差。如果使用HashSet<int>,查找时间复杂度为O(1),但相对较高的内存占用和哈希冲突仍然可能影响性能。

  • 位图算法 :查找时间复杂度为O(1),内存占用极低(仅需1000000/8 = 125000字节,即约122KB),且查找速度非常快,无论数据量多大,查找性能几乎不受影响。

相关推荐
程序员一诺几秒前
【深度学习】嘿马深度学习笔记第10篇:卷积神经网络,学习目标【附代码文档】
人工智能·python·深度学习·算法
刚学HTML2 小时前
leetcode 05 回文字符串
算法·leetcode
AC使者2 小时前
#B1630. 数字走向4
算法
冠位观测者2 小时前
【Leetcode 每日一题】2545. 根据第 K 场考试的分数排序
数据结构·算法·leetcode
古希腊掌管学习的神3 小时前
[搜广推]王树森推荐系统笔记——曝光过滤 & Bloom Filter
算法·推荐算法
qystca3 小时前
洛谷 P1706 全排列问题 C语言
算法
浊酒南街3 小时前
决策树(理论知识1)
算法·决策树·机器学习
就爱学编程3 小时前
重生之我在异世界学编程之C语言小项目:通讯录
c语言·开发语言·数据结构·算法
学术头条3 小时前
清华、智谱团队:探索 RLHF 的 scaling laws
人工智能·深度学习·算法·机器学习·语言模型·计算语言学
Schwertlilien4 小时前
图像处理-Ch4-频率域处理
算法