Bitmap

什么是bitmap?

来自于《编程珠玑》。所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素。由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省。
 
举个例子。我们要存储3,4,5,6,7这几个元素。如果用int[]来存储的话,我们需要5*32bit。我们知道int32默认值是0,它是由32个0组成的。这样的话我们能不能用它的每个bit位来存储一个数字呢?1-32位代表1-32这32个数字。而0代表不存在、1代表存在。这样的话,我们一个int32就可以存储32个数字了。话不多说,马上开搞。其实原理都非常简单~
 
   static void Main(string[] args)
        {
            BitMap map = new BitMap();
            map.Add(11);
            map.Add(22);
            map.Add(3);
            map.Add(7);
            map.Add(6);
            foreach (var item in map)
            {
                Console.WriteLine(item);
            }
        }

        public class BitMap : IEnumerable<int>
        {
            private int[] _bucket;
            public BitMap()
            {
                _bucket = new int[10];
            }

            private void Expand(int count)
            {
                var temp = new int[count];
                _bucket.CopyTo(temp, 0);
                _bucket = temp;
            }

            public void Add(int value)
            {
                int index = (value - 1) / 32;//得到在bucket中的下标
                if (index + 1 > _bucket.Length)//如果bucket太小,就进行扩充
                {
                    Expand(index + 1);
                }
                var item = _bucket[index];//获得对应位置中的元素
                var binary = Convert.ToString(item, 2).PadLeft(32, '0').Select(x => x.ToString()).ToList();//将item转换成2进制的字符串,再转换为list
                int bitindex = (value - 1) % 32;
                binary[bitindex] = "1";
                var binarystr = binary.Aggregate((x, y) => x + y);
                var result = Convert.ToInt32(binarystr, 2);
                _bucket[index] = result;
            }

            public IEnumerator<int> GetEnumerator()
            {
                for (int i = 0; i < _bucket.Length; i++)
                {
                    var item = _bucket[i];
                    if (item == 0)
                        continue;
                    string binary = Convert.ToString(item, 2).PadLeft(32, '0');
                    for (int j = 0; j < binary.Length; j++)
                    {
                        if (binary[j] == '1')
                        {
                            yield return i * 32 + j + 1;
                        }
                    }
                }
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                throw new NotImplementedException();
            }
        }

这样我们的bitmap就已经构造完成了。

当然,如果你懂位运算的话,我们还可以改成这样

  static void Main(string[] args)
        {
            BitMap map = new BitMap();
            map.Add(11);
            map.Add(22);
            map.Add(3);
            map.Add(7);
            map.Add(6);
            foreach (var item in map)
            {
                Console.WriteLine(item);
            }
        }

        public class BitMap : IEnumerable<int>
        {
            private int[] _bucket;
            public BitMap()
            {
                _bucket = new int[10];
            }

            private void Expand(int count)
            {
                var temp = new int[count];
                _bucket.CopyTo(temp, 0);
                _bucket = temp;
            }

            public void Add(int value)
            {
                int index = (value - 1) / 32;//得到在bucket中的下标
                if (index + 1 > _bucket.Length)//如果bucket太小,就进行扩充
                {
                    Expand(index + 1);
                }
                var item = _bucket[index];//获得对应位置中的元素
                int bitindex = (value - 1) % 32;//计算获得需要将哪个bit位置为1
                item = item | (1 << (31 - bitindex));//将对应的位置置为1
                _bucket[index] = item;
            }

            public IEnumerator<int> GetEnumerator()
            {
                for (int i = 0; i < _bucket.Length; i++)
                {
                    var item = _bucket[i];
                    if (item == 0)
                        continue;
                    for (int j = 0; j < 32; j++)
                    {
                        var step = 31 - j;
                        var temp = 1 << step;
                        if ((item & temp) == 0)
                            continue;
                        var result = i * 32 + j + 1;
                        yield return result;
                    }
                }
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                throw new NotImplementedException();
            }
        }

其实2组代码的实现效果都是一样的。但位运算是直接操作'位'的。所以性能会高点。

当然,bitmap也有缺点,如果有2个相同的元素,它没办法了。因为bit不是0就是1。

 
原文地址:https://www.cnblogs.com/irenebbkiss/p/4650495.html