算法之美——位图排序

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

 

问题描述:

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

 

解答:

首先回顾下计数排序:

算法之美——位图排序_第1张图片

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

线性的排序算法

 

位图排序:

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

算法之美——位图排序_第2张图片

 

具体思路:

算法之美——位图排序_第3张图片

 

•举例

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

算法之美——位图排序_第4张图片

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

怎么设置对应位为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,与其对应的字节,进行操作

算法之美——位图排序_第5张图片

 

优化

优化的原因
我们需要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实现了相同功能

算法之美——位图排序_第6张图片

 在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啊

你可能感兴趣的:(数据结构,优化,算法,Blog,存储,磁盘)