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;
    }
}

如果没看懂,这里是SetBit 和 GetBit 的实现细节

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),且查找速度非常快,无论数据量多大,查找性能几乎不受影响。

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值