• c# 用BitArray来管理包含关系


    BitArray是.net自带的引用类型,在名称空间Systems.Collections下面。输入BitArray可以看到它的摘要:“管理位值的压缩数组,该值表示为布尔值,其中 true 表示位是打开的 (1),false 表示位是关闭的 (0)”。

    定义一个BitArray:

    BitArray bitArr = new BitArray(10);
    bitArr[3] = true;
    bitArr[8] = true;

    历遍bitArr的成员,可以看到结果为{false,false,false,true,false,false,false,false,true,false}.

    BitArray由于引用类型的本质,可以重新设置大小。在结果数量不定而且总数可能大于32的情况下,比较适合用BitArray来管理包含关系。这里是相对BitVector32来讲的,BitVector32是值类型,而且固定大小32位,它具有数据处理更快的优点。可以根据实际情况来选择。对于这两种类型更多的解释,可以去msdn上查资料。

    包含的管理主要包括三个方面:新增,删除,包含判断。

    首先自定一个类,含有BitArray的私有字段,同时有Length的属性。

    public struct FlagsBitArray
    {
        BitArray _array;
        public int Length { get { return _array.Length; } }
    
        //构造函数
        public FlagsBitArray(int length)
        {
            _array = new BitArray(length);
        }
        //构造函数
        public FlagsBitArray(int[] arr)
        {
            if (arr == null) _array = new BitArray(0);
            else
            {
                var length = arr.Max();
                _array = new BitArray(length);
                AddFlag(arr);
            }
        }
    }

    可以将新增和删除理解成修改BitArray的相应索引处的bool值,新增改为true,删除改为false。

    void ModifyFlag(int[] arr, bool value)
    {
        if (arr == null) return;
        var max = arr.Max();
        if (max > _array.Length - 1)//如果提交的数字超出当前索引范围
            _array.Length = max + 1;
        foreach (var x in arr)
        {
            if (x >= 0) _array[x] = value;
            else throw new ArgumentException("负值无效");
        }
    }
    //加法
    public void AddFlag(params int[] newArr) { ModifyFlag(newArr, true); }
    
    //移除
    public void RemoveFlag(params int[] newArr) { ModifyFlag(newArr, false); }

    判断是否包含更加简单,只需要判断相应索引处的值是否为true。

    //判断有没有
    public bool HasFlag(int which)
    {
        //超出范围,返回false
        if (which < 0 || which > Length - 1) return false;
        return _array[which];
    }

     调用代码:

    var list = new int[] { 0, 1, 2, 3, 5, 8, 25, 30 };
    var arr = new FlagsBitArray(list);
    Console.WriteLine("包含25?" + arr.HasFlag(25));
    Console.WriteLine("包含20?" + arr.HasFlag(20));
    arr.AddFlag(10, 11, 12, 8, 32);
    Console.WriteLine(arr.Length);

    包含关系的管理,可以用很多方法。List集合、枚举的HasFlag、二进制与运算、BitVector32、BitArray等等。

    list集合属于最基本的方法,它可以实现添加删除和包含判断,但是数据的存储和处理时内存的开销较大;

    枚举的HasFlag和二进制与运算,以及BitVector32,它们的优点是数据的存储和内存开销较小。但都存在着Int位数限制的问题,枚举和二进制与运算可以通过long和BigInteger来处理,但总体不太灵活。在32位范围内,这三者都是比较有优势的。

    BitArray在长度上面比较占优势,可以无限扩充,这样的优势势必会拖累它的运算速度和内存开销,但是,BitArray里面包含了一个Int数组,每32位使用一个新整数。也就是说它占用的空间也是根据所包含的数据长度来调节的,所以整体影响应该不大。

    扩充类下面的一些其他函数 

    //还原包含的int集合
    public List<int> GetIntList()
    {
        List<int> res = new List<int>();
        for (int i = 0; i < _array.Length; i++)
            if (_array[i]) res.Add(i);
        return res;
    }
    
    //如果Length很大的时候,而且string需要存储到数据库时,可以考虑压缩算法。
    public override string ToString()
    {
        StringBuilder sb = new StringBuilder(this.Length) { Length = this.Length };
        for (int i = 0; i < this.Length; i++)
            sb[i] = this._array[i] ? '1' : '0';
        return sb.ToString();
    }
    
    //FlagsBitArray与String的转换
    public static implicit operator string(FlagsBitArray bitArr)
    {
        return bitArr.ToString();
    }
    
    //String与FlagsBitArray的隐式转换
    public static implicit operator FlagsBitArray(string str)
    {
        FlagsBitArray res = new FlagsBitArray(str.Length);
        for (int i = 0; i < str.Length; i++)
            res._array[i] = str[i] == '1';
        return res;
    }

    源代码

    转载请注明出处:http://www.cnblogs.com/icyJ/ 

  • 相关阅读:
    Java NIO(六)选择器
    Java NIO(五)套接字通道
    Java NIO(四)文件通道
    Java NIO(三)通道
    Java NIO(二)缓冲区
    Java NIO(一)概述
    gcc中的内嵌汇编语言(Intel i386平台)
    一些汇编指令
    403 Forbidden解决方案
    Linux从入门到放弃
  • 原文地址:https://www.cnblogs.com/icyJ/p/BitArray.html
Copyright © 2020-2023  润新知