您的位置:首页 > 产品设计 > UI/UE

编程珠玑之第二章questionA: 40亿个随机排列整数问题

2015-01-02 11:43 260 查看
问题描述:

A. 给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中的32位整数(在文件中至少缺失这样一个数——为什么?)。在具有足够内存的情况下,如何解决该问题?如果有几个外部的“临时”文件可用,但是仅有几百字节的内存,又该如何解决该问题?

问题解析:

1、首先要明白整型代表的范围如下:



由此看出一个无符号长整型大约表示43亿个数,所以大约有3亿个数是在此文件中不存在的,这样问题就明确了。

2、怎样生成包含40亿个随机排列的32位整数的顺序文件(假设里面数不重复)呢?

在windows系统下,RAND_MAX = 32767(0x7FFF); 我的Linux下RAND_MAX = 2147483647(0x7FFFFFFF). 在Windows下经过对rand()修改,这个范围可以增大,但由于不知道其实现算法,所以任何改变的都有可能改变输出值的概率,所以效果不是很理想,下面我在范围输出随机数范围[0, 65534],为什么不是65535?
因为我发现任何对rand()改变,其输出随机值的概率(如最大,最小值)都会有很多改变
,所以没有找到理想的方法,下面在勉强接受的范围内对上面问题做一个映射。

下面利用位图技术和C++的bitset输出在[0. 65534]范围内不重复的随机数:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

#include <iostream>

#include <bitset>

#include <cstdio>

#include <cstdlib> // srand, rand

#include <ctime> // time, clock_t

#include <cassert> // assert

#define MAX_16UINT 65535 // 最大的16无符号整型数(2^16-1)

#define MAX_RANDNUM 65000 // 最大的随机数个数

#define error( str ) fatal_error( str )

#define fatal_error( str ) fprintf( stderr, "%s\n", str ), exit( 1 )

using namespace std;

/************************************************************************/

// 函数名称:bigrand

// 函数目的:生成范围在[0, 65534]之间的随机整数

// 使用条件:RAND_MAX = 32767(0x7FFF)

/************************************************************************/

size_t bigrand()

{

assert(RAND_MAX == 0x7FFF);

return rand() + rand();

}

bitset<MAX_16UINT> mybits;

int main()

{

mybits.set(); // 默认所有位都置为1

printf("程序开始........\n");

clock_t start_time = clock(); // 开始时间

FILE* iofile = fopen("unsortfile.txt", "w");

if (NULL == iofile){ fatal_error("不能打开unsortfile.txt文件!\n"); }

size_t record = 0;

while (record != mybits.size()){

size_t index = bigrand();

// 输出值并将指定位置为0

if (mybits[index]){

fprintf(iofile, "%d\t", index);

mybits[index] = 0; record++; //printf("reords = %d", record);

}

// 测试生成最大和最小值概率

if ( index == 0 || index == 65534){ printf("index = %d\n", index); }

}

fclose(iofile);

clock_t end_time = clock(); // 结束时间

float cost_time = (float)(end_time - start_time) / CLOCKS_PER_SEC;

printf("bit位记录数:%d\n", mybits.size());

printf("全部it位重置为0耗时:%5.3f秒\n", cost_time);

return 0;

}

输出结果:



65535条数据都要这么长时间,跟别说40亿条数据了,所以需要大范围高效的随机数生成函数,C++11对随机数生成改进了不少,也比较复杂,也许可以在获得解答,可以查阅C++11 关于随机数的一些文档,以后有机会在研究!

解决方案:

1. 位图技术:

那么在有足够内存的情况下使用进行排序,查找缺失数就非常方便了!类似的解答可以参考第一章习题的解答:编程珠玑之第一章:开篇(习题)泛览 的习题2解答方案!

2. 二分搜索:

作者给出的方法是0/1探测法下的二分搜索,在不需要对所有数据的进行排序的情况下找出一个缺失的整数,我这里在小范围内做一个实现方案,当然在如此之大(40亿)的情况下还要具体修改。

如下:这里是使用0/1探测法找出所有小于20的缺失的整数:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

#include <iostream>

#include <bitset>

#include <vector>

#include <cstdio>

#include <cstdlib> // srand, rand

#include <ctime> // time, clock_t

#include <cassert> // assert

using namespace std;

/************************************************************************/

// 函数名称:getbit

// 函数返回:0或1

// 函数目的:找出value的pos比特位的值

// 使用条件:value范围是[0, 2^32-1]

/************************************************************************/

bool getbit(int32_t value, int32_t pos)

{

assert(pos >= 0 && pos < 32);

int32_t mask = 1; // 表示二进制掩码

int32_t value_32 = value;

return ((value_32 >> pos & mask) == mask);

}

/************************************************************************/

// 函数名称:find_missing_integers

// 函数返回:无

// 函数目的:找出小于max_counts(不包括)的所有缺失的整数

// 使用条件:vecints里面的数不重复, pos=0时,vetints里面最大值小于max_counts

/************************************************************************/

bitset<32> bit_missing_integer;

void find_missing_integers(const vector<int32_t>& vecints, const int32_t max_counts, int32_t pos=0)

{

// 计算相应bit位的0,1计数

int32_t counts_0 = 0, counts_1 = 0;

counts_0 = ceil(1.0 * max_counts / 2 ); // ceil向上取整

counts_1 = max_counts - counts_0;

vector<int32_t> vecints_0, vecints_1;

for (size_t i = 0; i != vecints.size(); ++i) {

if (!getbit(vecints[i], pos)) { vecints_0.push_back(vecints[i]); }

else { vecints_1.push_back(vecints[i]); }

}

// 第pos位缺1的情况

if (counts_1 - vecints_1.size() > 0){

bit_missing_integer[pos] = 1;

find_missing_integers(vecints_1, counts_1, pos + 1);

}

// 第pos位缺0的情况

if (counts_0 - vecints_0.size() > 0){

bit_missing_integer[pos] = 0;

if (counts_0 == 1 && counts_1 == 0){ // 临界位

printf("%ld\t", bit_missing_integer.to_ulong());

return;

}

else { // 递归调用

find_missing_integers(vecints_0, counts_0, pos + 1);

}

}

return;

}

void print_missing_integers()

{

int myints[5] = {1, 19, 4, 6, 18};

std::vector<int> myvecints(myints, myints + sizeof(myints) / sizeof(int) );

find_missing_integers(myvecints, 20);

return;

}

int main()

{

print_missing_integers();

return 0;

}
输出结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐