Bitmap算法

在全部具备性能优化的数据结构中,我想你们使用最多的就是hash表,是的,在具备定位查找上具备O(1)的常量时间,多么的简洁优美,算法

可是在特定的场合下:数组

①:对10亿个不重复的整数进行排序。性能优化

②:找出10亿个数字中重复的数字。服务器

固然我只有普通的服务器,就算2G的内存吧,在这种场景下,咱们该如何更好的挑选数据结构和算法呢?数据结构

 

一:问题分析数据结构和算法

     这年头,大牛们写的排序算法也就那么几个,首先咱们算下放在内存中要多少G: (10亿 * 32)/(1024*1024*1024*8)=3.6G,可怜ide

的2G内存直接爆掉,因此各类神马的数据结构都玩不起来了,固然使用外排序仍是能够解决问题的,因为要走IO因此暂时剔除,由于咱们性能

要玩高性能,无望后咱们想一想可不能够在二进制位上作些手脚?  优化

好比我要对{1,5,7,2}这四个byte类型的数字作排序,该怎么作呢?咱们知道byte是占8个bit位,其实咱们能够将数组中的值做为bit位的this

key,value用”0,1“来标识该key是否出现过?下面看图:

从图中咱们精彩的看到,咱们的数组值都已经做为byte中的key了,最后我只要遍历对应的bit位是否为1就能够了,那么天然就成有序数组了。

可能有人说,我增长一个13怎么办?很简单,一个字节能够存放8个数,那我只要两个byte就能够解决问题了。

能够看出我将一个线性的数组变成了一个bit位的二维矩阵,最终咱们须要的空间仅仅是:3.6G/32=0.1G便可,要注意的是bitmap排序不

是N的,而是取决于待排序数组中的最大值,在实际应用上关系也不大,好比我开10个线程去读byte数组,那么复杂度为:O(Max/10)。

 

二:代码

  我想bitmap的思想你们都清楚了,这一次又让咱们见证了二进制的魅力,固然这些移位都是位运算的工做了,熟悉了你就玩转了。

1:Clear方法(将数组的全部bit位置0)

   好比要将当前4对应的bit位置0的话,只须要1左移4位取反与B[0] & 便可。

复制代码
 1         #region 初始化所用的bit位为0
 2         /// <summary>
 3         /// 初始化所用的bit位为0
 4         /// </summary>
 5         /// <param name="i"></param>
 6         static void Clear(byte i)
 7         {
 8             //至关于 i%8 的功能
 9             var shift = i & 0x07;
10 
11             //计算应该放数组的下标
12             var arrindex = i >> 3;
13 
14             //则将当前byte中的指定bit位取0,&后其余对方数组bit位必然不变,这就是 1 的妙用
15             var bitPos = ~(1 << shift);
16 
17             //将数组中的指定bit位置一  “& 操做”
18             a[arrindex] &= (byte)(bitPos);
19         }
20         #endregion
复制代码

 

2:Add方法(将bit置1操做)

  一样也很简单,要将当前4对应的bit位置1的话,只须要1左移4位与B[0] | 便可。

复制代码
 1 #region 设置相应bit位上为1
 2         /// <summary>
 3         /// 设置相应bit位上为1
 4         /// </summary>
 5         /// <param name="i"></param>
 6         static void Add(byte i)
 7         {
 8             //至关于 i%8 的功能
 9             var shift = i & 0x07;
10 
11             //计算应该放数组的下标
12             var arrindex = i >> 3;
13 
14             //将byte中的 1 移动到i位
15             var bitPos = 1 << shift;
16 
17             //将数组中的指定bit位置一  “| 操做”
18             a[arrindex] |= (byte)bitPos;
19         }
20         #endregion
复制代码

 

2:Contain方法(判断当前bit位是不是1)

    若是看懂了Clear和Add,我相信最后一个方法已经不成问题了。

复制代码
 1         #region 判断当前的x在数组的位中是否存在
 2         /// <summary>
 3         ///判断当前的x在数组的位中是否存在
 4         /// </summary>
 5         /// <param name="i"></param>
 6         /// <returns></returns>
 7         static bool Contain(byte i)
 8         {
 9             var j = a[i >> 3] & (1 << (i & 0x07));
10 
11             if (j == 0)
12                 return false;
13             return true;
14         }
15         #endregion
复制代码

最后上总的代码:

复制代码
 1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Text;  5 using System.Diagnostics;  6 using System.Threading;  7 using System.IO;  8  9 namespace ConsoleApplication2 10 { 11 public class Program 12  { 13 static byte n = 7; 14 15 static byte[] a; 16 17 public static void Main() 18  { 19 //节省空间的作法 20 a = new byte[(n >> 3) + 1]; 21 22 for (byte i = 0; i < n; i++) 23  Clear(i); 24 25 Add(4); 26 Console.WriteLine("插入4成功!"); 27 28 var s = Contain(4); 29 30 Console.WriteLine("当前是否包含4:{0}", s); 31 32 s = Contain(5); 33 34 Console.WriteLine("当前是否包含5:{0}", s); 35 36  Console.Read(); 37  } 38 39 #region 初始化所用的bit位为0 40 /// <summary> 41 /// 初始化所用的bit位为0 42 /// </summary> 43 /// <param name="i"></param> 44 static void Clear(byte i) 45  { 46 //至关于 i%8 的功能 47 var shift = i & 0x07; 48 49 //计算应该放数组的下标 50 var arrindex = i >> 3; 51 52 //则将当前byte中的指定bit位取0,&后其余对方数组bit位必然不变,这就是 1 的妙用 53 var bitPos = ~(1 << shift); 54 55 //将数组中的指定bit位置一 “& 操做” 56 a[arrindex] &= (byte)(bitPos); 57  } 58 #endregion 59 60 #region 设置相应bit位上为1 61 /// <summary> 62 /// 设置相应bit位上为1 63 /// </summary> 64 /// <param name="i"></param> 65 static void Add(byte i) 66  { 67 //至关于 i%8 的功能 68 var shift = i & 0x07; 69 70 //计算应该放数组的下标 71 var arrindex = i >> 3; 72 73 //将byte中的 1 移动到i位 74 var bitPos = 1 << shift; 75 76 //将数组中的指定bit位置一 “| 操做” 77 a[arrindex] |= (byte)bitPos; 78  } 79 #endregion 80 81 #region 判断当前的x在数组的位中是否存在 82 /// <summary> 83 ///判断当前的x在数组的位中是否存在 84 /// </summary> 85 /// <param name="i"></param> 86 /// <returns></returns> 87 static bool Contain(byte i) 88  { 89 var j = a[i >> 3] & (1 << (i & 0x07)); 90 91 if (j == 0) 92 return false; 93 return true; 94  } 95 #endregion 96  } 97 }
复制代码

 

相关文章
相关标签/搜索