【C++】位排序算法

79 阅读2分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」。

简介

位排序灵感来源于二进制,用二进制数表示数字的存在状态。采用空间换时间的思想,把数据压缩到二进制状态表示,适用于海量去重排序,时间复杂度为O(n)O(n)

思路

以unsigned int类型(下文称uint)为例

  • uint类型在C语言中占用4字节即32比特,可以携带32位信息,那么这32位信息就可以表示32个连续整数的存在状态。
  • 若我们需要表示0~31这32个整数的存在状态,那么状态0表示无整数存在,状态1表示0存在,状态10表示1存在,状态11表示0、1存在……
  • 如图所示,这里101表示0、2数字存在。

  1. 即然1个uint可以表示32位数字,那么如果我们就可以用n个uint表示32*n个数字,用线性表把他们联系起来。原本的m个数字就会在空间上被压缩为m32\frac{m}{32}个数字。
  2. m32\frac{m}{32}个数字是线性的,当我们把数据依次读入线性表中时,就已经完成了排序,需要做的仅仅是遍历时顺序输出。
  3. 设unit的长度为L(即比特大小),num [ ]表示线性表,则第i个数字所在的存储块的索引方法为num [ i / L ],此时与i相对于本块的偏移长度i % L(i对L取模)进行位与运算num [ i / L ] & ( i % L ),即可得知是否存在数字i(存在反汇1,否则为0)。

参考代码

#include <stdio.h>
#include <string.h>
#define M 1000
typedef unsigned int uint;
uint group[M];//最大存取长度ML,即0~(ML-1)
#define L (sizeof(uint)*8)//每个存储单元的最大长度
bool ufind(int index)//查找index是否存在
{
    return group[index/L]&(1<<(index%L));
}
int main(){
    memset(group,0,sizeof(group));
    uint n,m,i,j;
    scanf("%d",&n);//n个数
    while(n--){
        scanf("%d",&m);
        if(!ufind(m))
            group[m/L]+=(1<<(m%L));
    }

    for(i=0;i<M;i++)
    {
        if(!group[i]) continue;//加快搜索,本存储块为空
        for(j=0;j<L;j++)
        {
            if(ufind(i*L+j))
                printf("%d ",i*L+j);
        }
    }
    return 0;
}
  • 样例输入
5
1
3
7
9
5
  • 样例输出
1 3 5 7 9
  • 运行截图