算法的力量:位运算在排序与搜索中的应用

简介:

楔子:
问题:假设一个文件中有9亿条不重复的9位整数,现在要求对这个文件进行排序。

一般解题思路:
1、将数据导入到内存中
2、将数据进行排序 (比如插入排序、快速排序)
3、将排序好的数据存入文件

难题:
一个整数为4个字节
即使使用数组也需要900,000,000 * 4byte = 3.4G内存
对于32位系统,访问2G以上的内存非常困难,而且一般设备也没有这么多的物理内存
将数据完全导入到内存中的做法不现实

其他解决办法:
1、导入数据库运算
2、分段排序运算
3、使用bit位运算

解决方案一:数据库排序
将文本文件导入到数据库,让数据库进行索引排序操作后提取数据到文件

优点:操作简单
缺点:运算速度慢,而且需要数据库设备。

解决方案二:分段排序
操作方式:
规定一个内存大小,比如200M,200M可以记录52428800条记录,我们可以每次提取5000万条记录到文件进行排序,要装满9位整数需要20次,所以一共要进行20次排序,需要对文件进行20次读操作

缺点:
 编码复杂,速度也慢(至少20次搜索)

关键步骤:
先将整个9位整数进行分段,亿条数据进行分成20段,每段5000万条
在文件中依次搜索0~5000万,50000001~1亿……
将排序的结果存入文件

解决方案三:bit位操作
思考下面的问题:
一个最大的9位整数为999999999
这9亿条数据是不重复的
可不可以把这些数据组成一个队列或数组,让它有0~999999999(10亿个)元素
数组下标表示数值,节点中用0表示这个数没有,1表示有这个数
判断0或1只用一个bit存储就够了

声明一个可以包含9位整数的bit数组(10亿),一共需要10亿/8=120M内存
把内存中的数据全部初始化为0
读取文件中的数据,并将数据放入内存。比如读到一个数据为341245909这个数据,那就先在内存中找到341245909这个bit,并将bit值置为1
遍历整个bit数组,将bit为1的数组下标存入文件

关键代码
检查是某一个char里面(first)的第second位中存储的数据是否为1

bool CompareBit (unsigned char first, int second)
{
 const static int mark_buf[] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};
 if (second > 8)
  return false;

 return  (first & mark_buf[second]) == mark_buf[second];
}

将某一个char(Desc)中的第source位置为1

bool WriteToBit (unsigned char *Desc, int source)
{
 const static int mark_buf[] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};

 if (source > 8)
  return false;

 Desc[0] |= mark_buf[source];

 return true;
}

案例
在某个项目中,我们需要对2亿条手机号码删除重复记录(过滤号码黑名单同样有效)

工作难点就在于如何处理这2亿条电话号码,直接用哈希表存放手机号码不大现实,即使经过优化,用一个unsigned int存放一条记录,那也得需要2亿*4=8亿byte,远超过32位系统的寻址能力

解决方案:
将电话号码由12位单个数字组成的字符串转换为一个unsigned int型数据(这个完全可能,手机号码由前三位数字和后面八位数字组成,后面八位需要占到1~1000万的空间,而前面用0~100的数字存储已经足够)
为简单起见,默认为0~4G的数字都有可能分布号码,为此我们分配4G/32=512M的内存
将这2亿个号码整理成unsigned int类型后按上述办法存放在这块内存中(比如13512345678我们整理后为112345678,我们找到内存中112345678bit的下标,并将此bit值设为1)
遍历整个bit数组,记录下所有的号码,这些号码即是不重复的手机号码

总结
建立一个足够大的bit数组当作hash表
以bit数组的下标来表示一个整数
以bit位中的0或1来表示这个整数是否在这个数组中存在
适用于无重复原始数据的搜索
原来每个整数需要4byte空间变为1bit,空间压缩率为32倍
扩展后可实现其他类型(包括重复数据)的搜索

注意
由于操作系统和编程语言本身的限制,有可能内存足够,但无法分配一块连续大内存的情况,这样的话可以申请多块稍微小一点的内存,然后用链表或其他的方式连接起来使用

目录
相关文章
|
21天前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
31 1
|
22天前
|
机器学习/深度学习 人工智能 算法
探索人工智能中的强化学习:原理、算法与应用
探索人工智能中的强化学习:原理、算法与应用
|
21天前
|
机器学习/深度学习 算法 数据挖掘
C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出
本文探讨了C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出。文章还介绍了C语言在知名机器学习库中的作用,以及与Python等语言结合使用的案例,展望了其未来发展的挑战与机遇。
39 1
|
21天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
49 1
|
1月前
|
缓存 算法 网络协议
OSPF的路由计算算法:原理与应用
OSPF的路由计算算法:原理与应用
45 4
|
28天前
|
机器学习/深度学习 监控 算法
基于反光衣和检测算法的应用探索
本文探讨了利用机器学习和计算机视觉技术进行反光衣检测的方法,涵盖图像预处理、目标检测与分类、特征提取等关键技术。通过YOLOv5等模型的训练与优化,展示了实现高效反光衣识别的完整流程,旨在提升智能检测系统的性能,应用于交通安全、工地监控等领域。
|
1月前
|
存储 算法 网络协议
OSPF的SPF算法介绍:原理、实现与应用
OSPF的SPF算法介绍:原理、实现与应用
76 3
|
22天前
|
机器学习/深度学习 人工智能 算法
探索人工智能中的强化学习:原理、算法及应用
探索人工智能中的强化学习:原理、算法及应用
|
15天前
|
算法
基于WOA算法的SVDD参数寻优matlab仿真
该程序利用鲸鱼优化算法(WOA)对支持向量数据描述(SVDD)模型的参数进行优化,以提高数据分类的准确性。通过MATLAB2022A实现,展示了不同信噪比(SNR)下模型的分类误差。WOA通过模拟鲸鱼捕食行为,动态调整SVDD参数,如惩罚因子C和核函数参数γ,以寻找最优参数组合,增强模型的鲁棒性和泛化能力。
|
1天前
|
供应链 算法 调度
排队算法的matlab仿真,带GUI界面
该程序使用MATLAB 2022A版本实现排队算法的仿真,并带有GUI界面。程序支持单队列单服务台、单队列多服务台和多队列多服务台三种排队方式。核心函数`func_mms2`通过模拟到达时间和服务时间,计算阻塞率和利用率。排队论研究系统中顾客和服务台的交互行为,广泛应用于通信网络、生产调度和服务行业等领域,旨在优化系统性能,减少等待时间,提高资源利用率。
下一篇
DataWorks