位排序

来源:互联网 发布:羽毛球场地预订软件 编辑:程序博客网 时间:2024/05/22 17:22

一.问题描述

输入:一个最多包含n个正整数的文件,每个数都小于n,且数据不重复,其中n = 10000000。

输出:按升序排列输出正数列表。

约束:最多有1MB的内存空间可用,有充足的磁盘存储空间可用。运行时间最多几分钟,运行时间为10秒就不需要进一步优化。

二.程序设计与实现概要

(1)如给定表示文件中整数集合的位图数据结构,则可以分三个阶段来编写程序

第一阶段:将所有的位都置为0,从而将集合初始化为空。

第二阶段:通过读入文件中的每个整数来建立集合,将每个对应的位置都置为1。

第三阶段:检验每一位,如果该为为1,就输出对应的整数,有此产生有序的输出文件。

 

(2)整个程序的思想就是:

1.每个整数有32位,那么它就可以表示32个数,分别对应每bit位为1.
2.然后把10000000个数分为1+N/BITSPERWORD组(相当于有这么多个桶),每组包含接近32个数。

(3)所申请的int数组如下所示:


(4)下面的C语言的实现和C++的实现代码

#include <stdio.h>#include <memory.h>#include <stdlib.h>#define N 10000000// 最大数#define BITSPERWORD 32<span style="white-space:pre"></span>// 宽度#define SHIFT 5#define MASK 0x1F// 字节位置 = 数据/32;(采用位运算即右移5位)// 位位置 = 数据%32;(采用位运算即跟0X1F进行与操作)// 将逻辑位置为i的二进制位置为1void set(int arr[], int i){    arr[i>>SHIFT] |= (1<<(i&MASK));// arr[i/32] = arr[i/32] | (1<<(i%32))}// 测试逻辑位置为i的二进制位是否为1int test(int arr[], int i){    return arr[i>>SHIFT] & (1<<(i&MASK));// arr[i/32] = arr[i/32] & (1<<(i%32))}// 将逻辑位置的二进制位置为0void clear(int arr[],int num){    memset(arr, 0x00, num*4);}int main(){int *arr;       // 用于存储元素是否存在    // 栈的最大空间一般为2M(与系统有关),因此要堆中分配arr = (int *)malloc(sizeof(int)*(N/BITSPERWORD+1));clear(arr,N/BITSPERWORD + 1);// 先在文本文件in.txt中生成N个数    FILE* in_file = freopen("in.txt", "r", stdin);    FILE* out_file = freopen("out.txt", "w", stdout);    if(in_file != NULL)    {        int d;        while(scanf("%d", &d) != EOF)            set(arr, d);        fclose(in_file);    }    if(out_file != NULL)    {        for(int i = 0; i < N; i++)            if(test(arr, i))                printf("%d\n", i);    }    fclose(out_file);    return 0;}

三.拓展

给40亿个不重复的unsigned int的整数,没有排过序,然后再给一个数,如果快速判断这个数是否在那40亿个数当中。(腾讯面试题)


用位图法:40亿unsigned int,则用位图表示的话需要大小为40亿个bit=4*109 bit=0.5*109 bytes 因此申请的内存只需要大小约为512MB左右,这样在内存每个bit代表一个unsignedint整数,并将每个bit初始化为0,然后将40亿个unsigned int的整数读入,每个unsigned int的整数对应bit设置为1,读入后,最后看所给定的数对应的bit是否为1,是1存在,否则不存在。







1 0
原创粉丝点击