算法之美——位图排序

辉爷在高级数据结构课程中讲解了位图排序。这是一种线性的排序算法,通过设置和清除二进制位实现排序。置1操作是通过或操作,置0操作则用与操作。讲解还涉及优化和在STL中的实现,展示了位图排序的广泛应用。

辉爷的高级数据结构开讲了,辉爷V5啊,今天辉爷讲的是位图排序

 

问题描述:

输入
给出至多10,000,000个正整数的序列
特征:
每个数都小于10,000,000
数据不重复且 数据之间不存在关联关系
输出:增序输出序列
约束:
内存容量1MB
磁盘空间充足
运行时间至多几分钟---最好线性时间

 

解答:

首先回顾下计数排序:

思想:
根据待排序中最大的数,开辟一个数组,记录每个整数出现的次数
遍历一遍待排序的数据(排序的过程)
顺序输出结果
要求
必须提前知道待排序数的最大数
缺点
有些数没有出现过,仍要为其保留一个空间
只能针对整数进行处理
优点

线性的排序算法

 

位图排序:

引入位图排序的原因
对计数排序算法进行空间压缩
思想
采用一个二进制位对应一个整数
前提
要知道待排序数的最大数
存储
使用字符或整形都可以

 

具体思路:

 

•举例

存储:位图使用字符数组存储
unsigned char bit[2];
可用字节有两个01字节,一个字节中有八位
我们只能表示16个数(0~15
问题
给出一个数,怎么判断其对应位图的位置
步骤
找到该数对应字节 +再找到该数对应
方法
14对应的字节14/8 = 1      
14对应的位:第14%8
14是存储在第1个字节上的第6号位
8是存储在第1个字节上的第0号位

 
已知:我们已找到待处理数所在的字节和位
问题:

怎么设置对应位为1或0,且不能影响其他位

思路:对其所在字节整体进行& |操作
1
1、先找到其所在字节bitmap[num>>3]
2、要把num对应位设为1即可
难点:
只把对应位为1,同时不影响该字节中的其他位
方法:
我们可以利用一个新的字节
把该字节上num对应的位设为1其他全为0
之后与其所在字节进行操作

 1<<(num & 0b111);// 1向左移动多少位


置1、置0的思想

1

让其对应的二进制位为1,其他为0,与其对应字节,进行操作

0

让其对应的二进制位为0,其他为1,与其对应的字节,进行操作

 

优化

优化的原因
我们需要10,000,000个数表示10,000,000个位
1MB的包含8*1024*1024个位
所需内存容量:10,000,000/(8*1024*1024) = 1.20MB
 
假如严格限制为1MB,可以采用的策略:
两次遍历待排序列
 
两次遍历待排序序列
思想:把数据分成两部分,分别执行位图排序
 
具体思路:
第一次对1- 5,000,000之间的数排序
之后再对5,000,001 -10,000,000之间的数排序
需要存储空间为:5,000,000/(8*1024*1024) = 0.596MB
总体上消耗的空间为0.596MB

 

位图排序使用范围及应用

位图排序使用范围
(1)非负整数
(2)每个整数最多出现一次
(3)最大整数小于N
(4)整数之间相互独立
 
相关应用
位图法存数据
使用位图法判断数是否存在重复
40亿个不重复的unsignedint的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中

 

在STL中,bitset实现了相同功能

 在STL中实现:

#include <bitset>
#include <iostream>

using namespace std;

int main()
{
	const int numcount = 10;
	const int MAXNUM = 20;
	int arr[numcount] = {2,20,13,7,2,18,16,5,1,0};
	
	bitset<MAXNUM+1> bitmap;
	//指定为置1
	for (int i=0; i<numcount; i++)
	{
		bitmap.set(arr[i]);
	}
	//输出排序结果;
	for (int i=0; i<MAXNUM; i++)
	{
		if (bitmap.test(i))
		{
			cout<<i<<" ";
		}
	}
}


再感叹一句,辉爷V5啊~ 辉爷blog啊

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值