经典算法题每日演练——第十一题 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位为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
最后上总的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.IO; namespace ConsoleApplication2
{
public class Program
{
static byte n = ; static byte[] a; public static void Main()
{
//节省空间的做法
a = new byte[(n >> ) + ]; for (byte i = ; i < n; i++)
Clear(i); Add();
Console.WriteLine("插入4成功!"); var s = Contain(); Console.WriteLine("当前是否包含4:{0}", s); s = Contain(); Console.WriteLine("当前是否包含5:{0}", s); Console.Read();
} #region 初始化所用的bit位为0
/// <summary>
/// 初始化所用的bit位为0
/// </summary>
/// <param name="i"></param>
static void Clear(byte i)
{
//相当于 i%8 的功能
var shift = i & 0x07; //计算应该放数组的下标
var arrindex = i >> ; //则将当前byte中的指定bit位取0,&后其他对方数组bit位必然不变,这就是 1 的妙用
var bitPos = ~( << shift); //将数组中的指定bit位置一 “& 操作”
a[arrindex] &= (byte)(bitPos);
}
#endregion #region 设置相应bit位上为1
/// <summary>
/// 设置相应bit位上为1
/// </summary>
/// <param name="i"></param>
static void Add(byte i)
{
//相当于 i%8 的功能
var shift = i & 0x07; //计算应该放数组的下标
var arrindex = i >> ; //将byte中的 1 移动到i位
var bitPos = << shift; //将数组中的指定bit位置一 “| 操作”
a[arrindex] |= (byte)bitPos;
}
#endregion #region 判断当前的x在数组的位中是否存在
/// <summary>
///判断当前的x在数组的位中是否存在
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
static bool Contain(byte i)
{
var j = a[i >> ] & ( << (i & 0x07)); if (j == )
return false;
return true;
}
#endregion
}
}

经典算法题每日演练——第十一题 Bitmap算法的更多相关文章
- 经典算法题每日演练——第十一题 Bitmap算法 (转)
http://www.cnblogs.com/huangxincheng/archive/2012/12/06/2804756.html 在所有具有性能优化的数据结构中,我想大家使用最多的就是hash ...
- 经典算法题每日演练——第十七题 Dijkstra算法
原文:经典算法题每日演练--第十七题 Dijkstra算法 或许在生活中,经常会碰到针对某一个问题,在众多的限制条件下,如何去寻找一个最优解?可能大家想到了很多诸如“线性规划”,“动态规划” 这些经典 ...
- 经典算法题每日演练——第八题 AC自动机
原文:经典算法题每日演练--第八题 AC自动机 上一篇我们说了单模式匹配算法KMP,现在我们有需求了,我要检查一篇文章中是否有某些敏感词,这其实就是多模式匹配的问题. 当然你也可以用KMP算法求出,那 ...
- 经典算法题每日演练——第六题 协同推荐SlopeOne 算法
原文:经典算法题每日演练--第六题 协同推荐SlopeOne 算法 相信大家对如下的Category都很熟悉,很多网站都有类似如下的功能,“商品推荐”,"猜你喜欢“,在实体店中我们有导购来为 ...
- 经典算法题每日演练——第七题 KMP算法
原文:经典算法题每日演练--第七题 KMP算法 在大学的时候,应该在数据结构里面都看过kmp算法吧,不知道有多少老师对该算法是一笔带过的,至少我们以前是的, 确实kmp算法还是有点饶人的,如果说红黑树 ...
- 经典算法题每日演练——第十六题 Kruskal算法
原文:经典算法题每日演练--第十六题 Kruskal算法 这篇我们看看第二种生成树的Kruskal算法,这个算法的魅力在于我们可以打一下算法和数据结构的组合拳,很有意思的. 一:思想 若存在M={0, ...
- 经典算法题每日演练——第十四题 Prim算法
原文:经典算法题每日演练--第十四题 Prim算法 图论在数据结构中是非常有趣而复杂的,作为web码农的我,在实际开发中一直没有找到它的使用场景,不像树那样的频繁使用,不过还是准备 仔细的把图论全部过 ...
- codeforces水题100道 第二十一题 Codeforces Beta Round #65 (Div. 2) A. Way Too Long Words (strings)
题目链接:http://www.codeforces.com/problemset/problem/71/A题意:将长字符串改成简写格式.C++代码: #include <string> ...
- codeforces水题100道 第十一题 Codeforces Round #143 (Div. 2) A. Team (brute force)
题目链接:http://www.codeforces.com/problemset/problem/231/A题意:问n道题目当中有多少道题目是至少两个人会的.C++代码: #include < ...
随机推荐
- FTP文件操作之下载文件
前面写了采用ftp上传文件,有了上传怎么能够没有下载呢?如果只有上传没有下载,那上传了也没啥用了.所以今天就跟大家一起学习学习使用ftp下载文件. 知道了怎么上传,那么下载也就变得很简单了,上传是把文 ...
- CC2530存储空间——Code
硬件平台:CC2530-F256 开发环境:IAR 8051(版本号 8.10) 參考: .<CC2530 User's Guide.pdf>(swru191c) .<IAR C/C ...
- 图表引擎AChartEngine 二
这几天项目涉及到android图表绘制,网上找的Demo都是大同小异,也就如上篇博文所写的一样是基本函数的实现.可是所有能找到的Demo都和设计图不符.木有办法,Leader发话啦,万不得已的情况下不 ...
- Hadoop入门进阶步步高(五)-搭建Hadoop集群
五.搭建Hadoop集群 上面的步骤,确认了单机能够运行Hadoop的伪分布运行,真正的分布式运行无非也就是多几台slave机器而已,配置方面的有一点点差别,配置起来就很easy了. 1.准备三台se ...
- iOS_67控件外观对照
iOS 7 button无边框,操作栏透明,控制器全屏 Tab Bar 对照 iOS 7 ...
- zabbix 实现curl 显示器
1.进入Configure->Templates 2. 新建一个模板 3.新建模板,并保存 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGFpND ...
- Chapter 1 Securing Your Server and Network(8):停止未使用的服务
原文:Chapter 1 Securing Your Server and Network(8):停止未使用的服务 原文出处:http://blog.csdn.net/dba_huangzj/arti ...
- 深入研究Java类载入机制
深入研究Java类载入机制 类载入是Java程序运行的第一步,研究类的载入有助于了解JVM运行过程,并指导开发人员採取更有效的措施配合程序运行. 研究类载入机制的第二个目的是让程序能动态的控制类载 ...
- unity3d c# 产生真正的随机数
虽然能够使用Random类来生成随机数.但它是系统时钟种子,因此,有大量的反复产生伪随机数的. 您可以使用RNGCryptoServiceProvider();相对真随机数生成. 由加密服务提供程序( ...
- C# Socket TCP Server & Client & nodejs client
要调试公司某项目里的一个功能,因为要准备测试环境,趁这个机会重温了一下Socket(全还给老师了 -_-#),做个备份. C# Server static void Main(string[] arg ...