经典算法题每日演练——第十一题 Bitmap算法
在所有具有性能优化的数据结构中,我想大家使用最多的就是hash表,是的,在具有定位查找上具有O(1)的常量时间,多么的简洁优美,
但是在特定的场合下:
①:对10亿个不重复的整数进行排序。
②:找出10亿个数字中重复的数字。
当然我只有普通的服务器,就算2G的内存吧,在这种场景下,我们该如何更好的挑选数据结构和算法呢?
一:问题分析
这年头,大牛们写的排序算法也就那么几个,首先我们算下放在内存中要多少G: (10亿 * 32)/(1024*1024*1024*8)=3.6G,可怜
的2G内存直接爆掉,所以各种神马的数据结构都玩不起来了,当然使用外排序还是可以解决问题的,由于要走IO所以暂时剔除,因为我们
要玩高性能,无望后我们想想可不可以在二进制位上做些手脚?
比如我要对{1,5,7,2}这四个byte类型的数字做排序,该怎么做呢?我们知道byte是占8个bit位,其实我们可以将数组中的值作为bit位的
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位为02 /// <summary>3 /// 初始化所用的bit位为04 /// </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位上为12 /// <summary>3 /// 设置相应bit位上为14 /// </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 }
经典算法题每日演练——第十一题 Bitmap算法相关推荐
- 经典算法题每日演练——第二十一题 十字链表
上一篇我们看了矩阵的顺序存储,这篇我们再看看一种链式存储方法"十字链表",当然目的都是一样,压缩空间. 一:概念 既然要用链表节点来模拟矩阵中的非零元素,肯定需要如下5个元素(ro ...
- 经典算法题每日演练——第六题 协同推荐SlopeOne 算法
原文:经典算法题每日演练--第六题 协同推荐SlopeOne 算法 相信大家对如下的Category都很熟悉,很多网站都有类似如下的功能,"商品推荐","猜你喜欢&quo ...
- 经典算法题每日演练——第十题 树状数组
原文:经典算法题每日演练--第十题 树状数组 有一种数据结构是神奇的,神秘的,它展现了位运算与数组结合的神奇魅力,太牛逼的,它就是树状数组,这种数据结构不是神人是发现不了的. 一:概序 假如我现在有个 ...
- 经典算法题每日演练——第七题 KMP算法
原文:经典算法题每日演练--第七题 KMP算法 在大学的时候,应该在数据结构里面都看过kmp算法吧,不知道有多少老师对该算法是一笔带过的,至少我们以前是的, 确实kmp算法还是有点饶人的,如果说红黑树 ...
- 经典算法题每日演练——第三题 猴子吃桃
猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾就多吃了一个.第二天早上又将剩下的桃子吃了一半,还是不过瘾又多 吃了一个.以后每天都吃前一天剩下的一半再加一个.到第10天刚好剩一个.问猴子第一天摘了多 ...
- 经典算法题每日演练——第五题 字符串相似度
原文地址:http://www.cnblogs.com/huangxincheng/archive/2012/11/11/2765633.html 这篇我们看看最长公共子序列的另一个版本,求字符串相似 ...
- 经典算法题每日演练——第二十二题 奇偶排序
原文:经典算法题每日演练--第二十二题 奇偶排序 这个专题因为各种原因好久没有继续下去了,MM吧...你懂的,嘿嘿,不过还得继续写下去,好长时间不写,有些东西有点生疏了, 这篇就从简单一点的一个&qu ...
- 经典算法题每日演练——第十九题 双端队列
经典算法题每日演练--第十九题 双端队列 原文:经典算法题每日演练--第十九题 双端队列 话说大学的时候老师说妹子比工作重要~,工作可以再换,妹子这个...所以...这两个月也就一直忙着Fall in ...
- 经典算法题每日演练——第一题 百钱买百鸡
经典算法题每日演练--第一题 百钱买百鸡 原文:经典算法题每日演练--第一题 百钱买百鸡 百钱买百鸡的问题算是一套非常经典的不定方程的问题,题目很简单:公鸡5文钱一只,母鸡3文钱一只,小鸡3只一文钱, ...
最新文章
- LinkedList源码(基础代码)
- js弹出窗体获得焦点
- P4445 最长回文串
- Html5中新增的表单元素详解
- 理解线程的挂起,sleep还有阻塞
- LinQ to entities 不能识别方法“system.string.ToString(system.String)”.因此该方法无法转换为存储表达式...
- 巴菲特:马斯克是伟大企业家,但特斯拉股票不是好投资标的
- 13.4 mysql用户管理 13.5 常用sql语句 13.6 mysql数据库备份恢复
- 基于RT1052的FlexSPI读写FLASH(W25Q256JV)
- DC中保存ddc格式文件(亲测有效!)save the unmapped design in ddc format
- 红米手机开启---开发者选项方法
- 通联数据举办公益讲座 探讨金融大数据发展机会
- python经典小程序-你用python写过那些好玩的微信小程序?
- 一个设想:什么是真正的云,及利用树莓派和cloudwall打造你的真正云中心
- 编译原理:文法和语言总结与梳理
- GUI自动化 - 识图定位
- 系统设计-网关(一)
- Nano Today(IF=21)| 北京大学齐宪荣团队通过原位重编程巨噬细胞增强肿瘤免疫治疗效果
- zara小程序怎么付款_能扫码付款并且可以打折的微信小程序怎么做?
- Windows编程语言VBA学习(二)——VBA基础