位排序算法


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;
}
原文地址:https://www.cnblogs.com/GeekDanny/p/13513215.html