C语言之位图排序

本文介绍了利用位图进行排序的算法,适用于大量不重复且数值范围有限的数据。通过建立位图,对每个数据在位图中对应位置标记,最后按顺序输出标记位,达到排序目的。以1亿个不超过10亿的整数为例,传统排序需要400M内存,而位图排序仅需30M左右,节省空间且速度快。文章提供了C语言的位图排序实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近对于位运算特别感兴趣,是因为看到了一段C代码,只有短短一行就实现了令人咂舌的效果。代码如下:

main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>
";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}

输出结果是当前时间的特殊显示。效果如下:

!!  !!!!!!              !!  !!!!!!              !!  !!!!!!
!!  !!  !!              !!      !!              !!  !!  !!
!!  !!  !!              !!      !!              !!  !!  !!
!!  !!!!!!    !!        !!      !!    !!        !!  !!!!!!
!!      !!              !!      !!              !!  !!  !!
!!      !!              !!      !!              !!  !!  !!
!!  !!!!!!              !!      !!              !!  !!!!!!

作者把原本要几十行甚至上百行的代码浓缩成一行,其中用到了递归和位图。这段代码理解起来很困难,也不是我这篇文章的主题。关于它的具体解析,请参看: http://www.youkuaiyun.com/article/2013-04-11/2814852-ioccc-a-clock-in-one-line

本文想介绍一下同样是利用位图实现的排序算法。它的强大之处在于,对于极其大量并且不重复的数据,可以用极小的内存代价实现排序。举个例子,比如有1亿个不重复并且其最大值不超过10亿的数据,如果用插入排序或快速排序等方式,单单就开辟一个存储1亿个整数的内存空间就需要4×1亿接近400M的内存空间,这是一个庞大的消耗。但是,这些数据最大不超过10亿并且没有重复的,我们可以用10亿位图(即共有10亿个位)来分别表示1-10亿,只要读到某个数就将其在位图中对应的某一位置1,最后将位值为1的位置按序输出,从而实现了排序效果。一个整数可以表示32位,那么我们最多只需要10亿/32+1个整数,大概只要30M的内存空间。所以在大量数据排序中位图排序确实是个非常有用的方法,既节省了空间,排序速度也是毋庸置疑的。

接下来具体介绍一下位图排序的原理。首先,需要一个10亿/32+1个整数的数组,我们会用到这些整数的二进制形式,只要知道是这个数组中的第几个整数以及这个整数的第几位,就可以计算出该位对应的是哪一个目标整数。比如,9999在位图中的位置是,数组中第9999/32(结果取整)个整数,该整数的第9999%32(即取余)位。接下就看看如何用程序语言实现位图排序,下面是C的实现代码:

#include <stdio.h>
#define MAX 1000000000
#define N ((MAX%32==0) ? (MAX/32) : (MAX/32+1))
#define SHIFT 5           
#define MASK 0x1F

int bit[N];
//此方法将目标为置为1
//i右移5位求出整数在数组中的位置,i&MASK对32取余即求出位在整数中的位置,
//最后1左移的结果与当前数组元素进行或操作,得到将第i位置1后的整数  
void set(int i)
{
    bit[i>>SHIFT]=bit[i>>SHIFT]|(1<<(i&MASK));     
} 

//初始将所有位置0,原理同set 
void clear()
{
	int i;
	for(i=1;i<=MAX;i++)
    {
         bit[i>>SHIFT]=bit[i>>SHIFT]&(~(1<<(i&MASK)));  
    }    
}

//判断位是否为1,是的话返回对应的整数
int test(int i)
{
    return bit[i>>SHIFT] & (1<<(i&MASK));        
}

int main(int argc, char *argv[])
{
    int i;

    clear();
    
    //输入几个数测试排序结果
    while(scanf("%d",&i)!=EOF)
    {
        set(i);
    }

    for(i=1;i<=MAX;i++)
    {
        if(test(i))
            printf("%d ",i);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值