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

相关推荐
Iceberg_wWzZ1 分钟前
数据结构(Day14)
linux·c语言·数据结构·算法
夏天天天天天天天#6 分钟前
求Huffman树及其matlab程序详解
算法·matlab·图论
Infedium15 分钟前
优数:助力更高效的边缘计算
算法·业界资讯
student.J35 分钟前
傅里叶变换
python·算法·傅里叶
五味香41 分钟前
C++学习,动态内存
java·c语言·开发语言·jvm·c++·学习·算法
Beauty.5681 小时前
P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布
数据结构·c++·算法
Aurora20051 小时前
蓝桥杯2024省C
c语言·算法·蓝桥杯
爱棋笑谦1 小时前
二叉树计算
java·开发语言·数据结构·算法·华为od·面试
小鱼在乎1 小时前
动态规划---最长回文子序列
算法·动态规划
xiaobai12 31 小时前
二叉树的遍历【C++】
开发语言·c++·算法