基于C#实现Bitmap算法

在所有具有性能优化的数据结构中,我想大家使用最多的就是 hash 表,是的,在具有定位查找上具有 O(1)的常量时间,多么的简洁优美,但是在特定的场合下:
①:对 10 亿个不重复的整数进行排序。
②:找出 10 亿个数字中重复的数字。
当然我只有普通的服务器,就算 2G 的内存吧,在这种场景下,我们该如何更好的挑选数据结构和算法呢?

一、问题分析

这年头,大牛们写的排序算法也就那么几个,首先我们算下放在内存中要多少 G:
(10 亿 * 32)/(102410241024*8)=3.6G,可怜的 2G 内存直接爆掉,所以各种神马的数据结构都玩不起来了,当然使用外排序还是可以解决问题的,由于要走 IO 所以暂时剔除,因为我们要玩高性能,无望后我们想想可不可以在二进制位上做些手脚?
比如我要对{1,5,7,2}这四个 byte 类型的数字做排序,该怎么做呢?我们知道 byte 是占 8 个 bit 位,其实我们可以将数组中的值作为 bit 位的 key,value 用”0,1“来标识该 key 是否出现过?下面看图:
image.png
从图中我们精彩的看到,我们的数组值都已经作为 byte 中的 key 了,最后我只要遍历对应的 bit 位是否为 1 就可以了,那么自然就成有序数组了。
可能有人说,我增加一个 13 怎么办?很简单,一个字节可以存放 8 个数,那我只要两个 byte 就可以解决问题了。
image.png
可以看出我将一个线性的数组变成了一个 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] & 即可。
image.png

 #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 >> 3;

     //则将当前byte中的指定bit位取0,&后其他对方数组bit位必然不变,这就是 1 的妙用
     var bitPos = ~(1 << shift);

     //将数组中的指定bit位置一  “& 操作”
     a[arrindex] &= (byte)(bitPos);
 }
 #endregion

2、Add 方法(将 bit 置 1 操作)

同样也很简单,要将当前 4 对应的 bit 位置 1 的话,只需要 1 左移 4 位与 B[0] | 即可。
image.png

 #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 >> 3;

     //将byte中的 1 移动到i位
     var bitPos = 1 << shift;

     //将数组中的指定bit位置一  “| 操作”
     a[arrindex] |= (byte)bitPos;
 }
 #endregion

3、Contain 方法(判断当前 bit 位是否是 1)

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

 #region 判断当前的x在数组的位中是否存在
 /// <summary>
 ///判断当前的x在数组的位中是否存在
 /// </summary>
 /// <param name="i"></param>
 /// <returns></returns>
 static bool Contain(byte i)
 {
     var j = a[i >> 3] & (1 << (i & 0x07));

     if (j == 0)
         return false;
     return true;
 }
 #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 = 7;
 
         static byte[] a;
 
         public static void Main()
         {
             //节省空间的做法
             a = new byte[(n >> 3) + 1];
 
             for (byte i = 0; i < n; i++)
                 Clear(i);
 
             Add(4);
             Console.WriteLine("插入4成功!");
 
             var s = Contain(4);
 
             Console.WriteLine("当前是否包含4:{0}", s);
 
             s = Contain(5);
 
             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 >> 3;
 
             //则将当前byte中的指定bit位取0,&后其他对方数组bit位必然不变,这就是 1 的妙用
             var bitPos = ~(1 << 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 >> 3;
 
             //将byte中的 1 移动到i位
             var bitPos = 1 << 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 >> 3] & (1 << (i & 0x07));
 
             if (j == 0)
                 return false;
             return true;
         }
         #endregion
     }
 }

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/176183.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

做Python自动化测试,我教你个方法还能快一倍!

如果你学过 python 进行自动化测试&#xff0c;你一定使用过 unittest。 今天我们要讲的 nose2 是一个高级版本的 unittest。他比 unittest 更容易理解&#xff0c;用起来也更加方便一些。 快速开始 nose2 在 unittest 的基础上开发的&#xff0c;所以如果你之前是用 unitte…

python 水质日历热力图

利用日历热力图可以方便的查看站点水质全年的变化情况。 接口获取站点数据 这一步根据自己实际情况&#xff0c;也可以读取excel、MySQL读取数据。这里把API地址已隐去。 import numpy as np import calendar import requests import json import pandas as pd import time f…

python基于GCN(图卷积神经网络模型)和LSTM(长短期记忆神经网络模型)开发构建污染物时间序列预测模型

在以往的时间序列预测建模中广泛使用的是回归类算法模型和RNN类的算法模型&#xff0c;相对来说技术栈会更稳定一些&#xff0c;最近有一个实际业务场景的需求&#xff0c;在建模的过程中要综合考虑其余点位的影响依赖&#xff0c;这时候我想到了之前做过的交通流量和速度预测相…

全国第一届学生(青年)运动会女子拳击比赛60公斤冠军载誉归来

11月16日&#xff0c;参加全国第一届学生&#xff08;青年&#xff09;运动会女子拳击比赛60公斤冠军阿依古再丽麦合苏提抵达和田。 中华人民共和国第一届学生&#xff08;青年&#xff09;运动会拳击比赛11月12日在广西贺州市钟山县体育馆落下帷幕&#xff0c;本届比赛新疆拳击…

60V降压恒流芯片 高调光比LED驱动器 SL6015B替代PT4115 电路简单

在LED照明领域&#xff0c;降压恒流芯片是一种非常重要的芯片&#xff0c;它可以将输入的电压降低并输出稳定的电流&#xff0c;从而为LED灯提供合适的驱动电源。其中&#xff0c;SL6015B是一款非常优秀的降压恒流芯片&#xff0c;它具有高调光比、简单的电路设计、低成本的优点…

服务案例|故障频发的一周,居然睡得更香!

医院运维有多忙&#xff1f; 医院运维&#xff0c;听起来平平无奇毫不惊艳&#xff0c;但其中的含金量&#xff0c;可不是“维持系统正常运行”就能总结的。毕竟医院对业务连续性的超高要求&#xff0c;让运维面对的问题都是暂时的&#xff0c;下一秒可能就有新问题需要发现解…

一般人用 Linux 算是找虐吗?

一般人用 Linux 算是找虐吗&#xff1f; 主要得看用什么Linux&#xff0c;毕竟Android也算是Linux&#xff0c;满大街一般人整天在用&#xff0c;也没什么人觉得自己在找虐。 最近很多小伙伴找我&#xff0c;说想要一些Linux的资料&#xff0c;然后我根据自己从业十年经验&…

【Linux】:进程间通信和日志模拟

进程间通信 一.基本概念二.简单的通信-管道(匿名管道)1.建立通信信道2.通信接口 三.命名管道三.模拟命名管道通信&#xff08;加上日志&#xff09;1.完整代码2.基本使用 一.基本概念 是什么 两个或多个进程实现数据层面的交互。 因为进程独立性的存在&#xff0c;导致进程间…

spark shuffle 剖析

ShuffleExchangeExec private lazy val writeMetrics SQLShuffleWriteMetricsReporter.createShuffleWriteMetrics(sparkContext)private[sql] lazy val readMetrics SQLShuffleReadMetricsReporter.createShuffleReadMetrics(sparkContext)用在了两个地方&#xff0c;承接的是…

禁止安装新软件怎么设置(超详细图文介绍)

很多公司的网管向我们反应&#xff0c;总是有员工随意下载软件&#xff0c;并且不去正规网站、正规官网下载&#xff0c;导致公司的电脑总是又卡又慢&#xff0c;网管的工作很难开展。 此时就需要对公司安装软件的情况&#xff0c;进行统一管控了。 方法一&#xff1a;适合个人…

Git - 版本控制系统

目录 一、概述 配置用户信息 二、Git仓库 创建 本地仓库 git的三个区域 示例 Git文件状态 举例 三、区域使用 暂存区使用 版本库使用 文件忽略 四、分支 步骤 合并与删除 步骤 合并与提交 合并冲突 五、常用指令 六、Git远程仓库 使用步骤 克隆 同步 …

一键合并多个TXT文本,将保存在TXT的快递单号进行一键合并

如果你需要处理大量的TXT文本文件&#xff0c;那么你可能会遇到需要将这些文件合并为一个文件的情况。这不仅涉及到文件的组织和管理&#xff0c;还可能涉及到文件内容的连贯性和完整性。现在&#xff0c;我们有一个强大的工具&#xff0c;可以帮助你轻松实现一键文件整理&…

身份证号码校验

根据《新版外国人永久居留身份证适配性改造要点》&#xff0c;公司需要把代码中对身份证的校验进行优化 就文档内容可以看到需要优化的要点是&#xff1a; 新版永居证号码以 9 开头 受理地区代码出生日期顺序码校验码&#xff1b;&#xff08;共18位&#xff09; eg&#xff…

2023年约特干故城夜间演艺《万方乐奏有于阗》完美谢幕

11月19日&#xff0c;记者走进约特干故城看到演员在欢乐地跳着刀郎舞和古典舞&#xff0c;庆祝今年以来夜间演艺《万方乐奏有于阗》演出200场完美谢幕。 11月19日在约特干故城&#xff0c;演员正在表演迎宾乐舞。阿卜力克木依卜拉依木摄 当天晚上&#xff0c;城楼上旌旗猎猎&am…

Transmit v5.10.3(FTP客户端)

Transmit 5是一款由Panic开发的功能强大的FTP(文件传输协议)客户端软件&#xff0c;专为 macOS 平台设计。它提供了简单、直观的界面和丰富的功能&#xff0c;使用户能够轻松地管理和传输文件。 在文件传输和同步方面&#xff0c;Transmit 5提供了强大的文件同步功能&#xff…

18张值得收藏的高清卫星影像

这里分享的18张高清卫星影像&#xff0c;由吉林一号卫星拍摄。 原图来自长光卫星嘉宾在直播中分享的PPT演示文档。 18张高清卫星影像 吉林一号高分04A星&#xff0c;于2022年05月21日拍摄的北京紫禁城高清卫星影像。 北京紫禁城 云南昆明滇池国际会展中心高清卫星影像&…

【STM32外设系列】JW01三合一空气质量检测模块

&#x1f380; 文章作者&#xff1a;二土电子 &#x1f338; 关注公众号获取更多资料&#xff01; &#x1f438; 期待大家一起学习交流&#xff01; 文章目录 一、JW01模块简介二、数据格式介绍三、程序设计3.1 串口初始化3.2 串口接收中断服务函数3.3 数据解析函数 四、其他…

思福迪 运维安全管理系统 test_qrcode_b 远程命令执行漏洞

思福迪 运维安全管理系统 test_qrcode_b 远程命令执行漏洞 一、漏洞描述二、漏洞影响三、网络测绘四、漏洞复现1.手动复现2.自动化复现3.python源代码 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任…

OOM问题排查+Jvm优化

OOM问题排查&#xff1a; 1、top命令&#xff1a;查看cpu和内存的使用情况。 2、jstat命令&#xff1a;查看YGC和FGC情况&#xff0c;一般都是老年代不够用。导致OOM 3、jmap命令&#xff1a; 查看哪个类的实例过多,以每个类占用多少了内存。4、jstack 查看线程与线程之间的阻…

【广州华锐互动】昆虫3D虚拟动态展示:探索神奇的微观世界

在这个充满科技魅力的时代&#xff0c;我们可以通过各种方式去了解和探索自然界的奥秘。而昆虫作为地球上最为丰富多样的生物群体之一&#xff0c;其独特的生活习性和形态特征一直吸引着人们的目光。 由广州华锐互动开发的昆虫3D虚拟动态展示系统&#xff0c;成为了一种全新的科…