title: 位图数据结构-位排序算法
date: 2020-08-16
tags: 算法;位排序
位排序算法,一种占用内存小、运行时间快应用于特殊情况的算法
0x01.问题背景
- 问题描述:需要对磁盘中的文件进行排序,对时间效率要求高,文件中包含千万条记录,每条记录都是7位整数(百万)号码
整数记录数据不重复,每条记录都是单一数据。 - 输入:一个包含N个整数的文件,每个数都小于N=10^7,整数无重复
- 输出:将输入的整数进行升序排序,输出有序的列表
- 约束条件:大约有1MB的内存空间可用,充足的磁盘空间,时间控制在10s-8min之间
0x02.解决方法
1.归并排序
磁盘文件最常用的排序算法就是归并排序,但是对于千万数量级别的数据,运行时间是以天为单位
// 归并排序算法实现
int mergeSortCore(int[] &array,int lo,int mid,int hi)
{
int len=array.size(); // 数组长度
// 将数组进行备份
int compare[array.size()];
for(int k=0;k<len;k++)
{
compare[k]=array[k];
}
// 双指针进行比较赋值
int i=lo;
int j=mid+1;
for(int k=lo;k<=hi;k++)
{
if(i>mid) array[k]=compare[j++];
else if(j>hi) array[k]=compare[i++];
else if(compare[i]>compare[j]) array[k]=compare[j++];
else array[k]=compare[i++];
}
}
void mergeSort(int[] &arr,int left,int right)
{
if(left>right) return;
int mid=(left+right)/2;
mergeSort(arr,left,mid);
mergeSort(arr,mid+1,right);
mergeSortCore(arr,left,mid,right);
}
void sort(int []arr)
{
mergeSort(arr,0,arr.size());
}
2.分治+快速排序
1MB的内存空间
1MB=1024KB=1024x1024=1048576 byte
每个数是7位百万级别的整数
32bit=4byte可以表示的范围(04294967296,-21474836482147483647)
1048576/4=262144
10^7/40=250000
-
解决办法:1MB大概可以存储250000个整数号码,将N=10^7文件分成40子文件
(0249999,250000499999,...,9750000~999999),遍历输入40次
每次的排序算法使用快速排序,达到效率最高 -
快速排序
快速排序最重要的是找到partition函数
// define the swap function
void swap(int[] &arr,int lo,int hi)
{
int temp=arr[lo];
arr[lo]=arr[hi];
arr[hi]=temp;
}
int partiton(int[] &arr,int left,int right)
{
// define the flag value and two pointer
int flag=arr[left];
int i=left+1;
int j=right;
// swap the value base the flag
// need TODO
// optimize
while(i<j){
if(arr[i]>flag && arr[j]<flag)
{
swap(arr,i,j);
i++;
j--;
}
else if(arr[i]<flag && arr[j]<flag)
{
i++;
}
else if(arr[i]>flag && arr[j]>flag)
{
j--;
}
else
{
i++;
j--;
}
}
swap(arr,lo,j);
return j;
}
// optimization partition function
int optPartition(int[] &arr,int lo,int hi)
{
int flag=arr[lo];
// 注意这两个指针的开始位置
int i=lo;
int j=hi+1;
while(true)
{
while(arr[++i]<flag) if(i==hi) break;
while(flag<arr[--j]) if(j==lo) break;
if(i>=j) break;
swap(arr,i,j);
}
// 将flag放入正确的位置
swap(arr,lo,j);
return j;
}
void QuickSort(int[] &arr,int lo,int hi)
{
// break the recursive
if(lo>=hi)
{
return;
}
int index=partiton(arr,lo,hi);
QuickSort(arr,lo,index-1);
QuickSort(arr,index+1,hi);
}
void sort(int[] &arr)
{
QuickSort(arr,0,arr.size());
}
3.位排序算法
使用位图(位向量)来表示集合,用百万bit位的字符串来表示
01010001100 这个字符串表示{2,4,8,9}四个数存在(下标位置)
- 1.构建一个长度可以满足要求的bitarray,所有位置全部置0
- 2.输入数字,找到对应的下标,并改为1
- 3.遍历bitarray,只要是位置为1就进行输出
10^7/8=1250000 大概是1.19MB,内存大小刚刚够
// 伪代码,没有考虑文件的输入输出
// 定义数组也是不对,只是为了说明问题
#include<string>
#define MAX_VLAUE 10000000
int main()
{
string bitarray[MAX_VLAUE];
// first step
for(int i=0;i<MAX_VLAUE;i++)
{
bitarray[i]=0;
}
// second step
// TODO condtion 表示文件中存在这个数
for(int i=0;i<MAX_VLAUE && condition ;i++){
bitarray[i]=1;
}
// third step
for(int i=0;i<MAX_VLAUE && bitarray[i]==1;i++){
printf("%d
",i);
}
return 0;
}