编程珠玑 第一章 位图排序算法

位图排序是一种效率极高(复杂度可达O(n))并且很节省空间的一种排序方法,但是这种排序方法对输入的数据是有比较严格的要求(数据不能重复,大致知道数据的范围)。位图排序即利用位图或者位向量来表示集合。举个例子,假如有一个集合{3,5,7,8,2,1},我们可以用一个8位的二进制向量set[1-8]来表示该集合,如果数据存在,则将set相对应的二进制位置1,否则置0.根据给出的集合得到的set为{1,1,1,0,1,0,1,1},然后再根据set集合的值输出对应的下标即可得到集合{3,5,7,8,2,1}的排序结果。这个就是位图排序的原理。

一.位图排序的应用:

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

      因为unsigned int数据的最大范围在在40亿左右,40*10^8/1024*1024*8=476,因此只需申请512M的内存空间,每个bit位表示一个unsigned int。读入40亿个数,并设置相应的bit位为1.然后读取要查询的数,查看该bit是否为1,是1则存在,否则不存在。

      2.给40亿个unsigned int的整数,如何判断这40亿个数中哪些数重复?

      同理,可以申请512M的内存空间,然后读取40亿个整数,并且将相应的bit位置1。如果是第一次读取某个数据,则在将该bit位置1之前,此bit位必定是0;如果是第二次读取该数据,则可根据相应的bit位是否为1判断该数据是否重复。

二.位图排序的实现

     由于在C语言中没有bit这种数据类型,因此必须通过位操作来实现。

     假如有若干个不重复的正整数,范围在[1-100]之间,因此可以申请一个int数组,int数组大小为100/32+1。

编程珠玑 第一章 位图排序算法

假如有数据32,则应该将逻辑下标为32的二进制位置1,这个逻辑位置在A[1]的最低位(第0位)。

因此要进行置1位操作,必须先确定逻辑位置:字节位置(数组下标)和位位置。

字节位置=数据/32;(采用位运算即右移5位)

位位置=数据%32;(采用位运算即跟0X1F进行与操作)。

其他操作如清0和判断两个操作类似。

引自:http://www.cnblogs.com/dolphin0520/archive/2011/10/19/2217369.html

位图排序头文件:

1 #define true 1

2 #define false 0

3 typedef int bool;

4 void set_bit(unsigned int *bitmap,unsigned int k);

5 void clear_bit(unsigned int *bitmap,unsigned int k);

6 bool test_bit(unsigned int *bitmap,unsigned int k);

7 bool init_bitmap(unsigned int **bitmap,unsigned int n);

 

位图排序实现文件:

 1 //bitmap_sort.c 文件

 2 //实现位图排序功能

 3 #include <stdio.h>

 4 #include <stdlib.h>

 5 #include <memory.h>

 6 #include "bitmap_sort.h"

 7 #define BITSPERWORD 32

 8 #define SHIFT 5

 9 #define MASK 0x1F

10 

11 

12 // 数字k所对应位图的位置置为1

13 void set_bit(unsigned int *bitmap,unsigned int k)

14 {

15     unsigned int byte_position;

16     unsigned short bit_position;

17     byte_position = k >> 5//byte_position表示k在位图中的字节

18     bit_position = k & 0x1F;//bit_position表示k所在字节的位

19     /*printf("byte = %d    bit = %d\n", byte_position, bit_position);*/

20     bitmap[byte_position] = bitmap[byte_position] | (1 << bit_position);

21 }

22 

23 //数字k所对应位图的位置清零

24 void clear_bit(unsigned int *bitmap,unsigned int k)

25 {

26     unsigned int byte_position;

27     unsigned short bit_position;

28     byte_position = k >> 5;

29     bit_position = k & 0x1F;

30     /*printf("byte = %d    bit = %d\n", byte_position, bit_position);*/

31     bitmap[byte_position] = bitmap[byte_position] & ~(1 << bit_position);

32 }

33 

34 //测试数字k所对应位图的位置为1或为0

35 bool test_bit(unsigned int *bitmap,unsigned int k)

36 {

37     unsigned int byte_position;

38     unsigned short bit_position;

39     byte_position = k >> 5;

40     bit_position = k & 0x1F;

41     /*printf("byte = %d    bit = %d\n", byte_position, bit_position);*/

42     return bitmap[byte_position] & (1 << bit_position);

43 }

44 

45 //初始化位图

46 bool init_bitmap(unsigned int **bitmap, unsigned int n)

47 {

48     unsigned int size = 1 + n/BITSPERWORD, i;

49     printf("n = %u    size = %u\n", n, size);

50     *bitmap = (unsigned int *)malloc(size*sizeof(unsigned int));

51     if(*bitmap == NULL)

52     {

53         printf("Failed to malloc\n");

54         return false;

55     }

56     //数据初始化

57     /*for(i = 1 ; i <=n; i ++)

58         clear_bit(*bitmap, i);

59     */

60     //新开辟的空间均初始化为零

61     memset(*bitmap, 0, size*sizeof(unsigned int));

62     return true;

63 }

位排序测试文件:

  1 #include<stdio.h>

  2 #include<stdlib.h>

  3 #include "bitmap_sort.h"

  4 //从文件proc读入数据,添加到位图中,文件的中格式是以空格隔开的,例如10 20 2。

  5 //proc        读取文件指针

  6 //n            位图大小

  7 //bitmap    位图集合

  8 bool in_process(FILE *proc, unsigned int n, unsigned int *bitmap)

  9 {

 10     unsigned int k;

 11     printf("in process\n");

 12     while(!feof(proc))

 13     {

 14         if(!fscanf(proc, "%u ", &k))//读取整数

 15         {

 16             printf("when input data from file, some error happened!\n");

 17             return false;

 18         }

 19         else if( k > n) //整数是否在范围内

 20         {

 21             printf("data upper overflow!\n");

 22             return false;

 23         }

 24         else

 25         {

 26             printf("data = %u\n", k);

 27             set_bit(bitmap,k);

 28         }

 29     }

 30     return true;

 31     

 32 }

 33 //从位图读取数据,写入到proc文件中

 34 //proc        写入文件指针

 35 //n            位图大小

 36 //bitmap    位图集合

 37 

 38 bool out_process(FILE *proc, unsigned int n, unsigned int *bitmap)

 39 {

 40     unsigned int i, k;

 41     printf("out process\n");

 42     for(i = 1; i <= n; i ++)

 43     {

 44         if(!test_bit(bitmap, i))

 45             continue;

 46         else if(feof(proc))//检测文件结束

 47         {

 48             printf("when output data into  flie, some errors happened!\n");

 49             return false;

 50         }

 51         else

 52         {

 53             printf("data = %u\n", i);

 54             fprintf(proc, "%u ", i);

 55         }

 56         

 57     }

 58     return true;

 59 }

 60 

 61 //函数调用需要三个参数: 位图大小 输入文件 输出文件

 62 int main(int argc, char *argv[])

 63 {

 64     unsigned int *bitmap;

 65     FILE *in, *out;

 66     if(argc != 4)

 67     {

 68         printf("Usage: %s n infile outfile\n", argv[0]);

 69         return -1;

 70     }

 71     

 72     

 73     unsigned int size = atoi(argv[1]);

 74     

 75     if((in = fopen(argv[2], "r")) == NULL)

 76     {

 77         printf("open infile failed\n");

 78         fclose(in);

 79         return -1;

 80     }

 81     if((out = fopen(argv[3], "w")) == NULL)

 82     {

 83         printf("open outfile failed\n");

 84         fclose(out);

 85         return -1;

 86     }

 87     

 88     

 89     if(!init_bitmap(&bitmap, size))

 90     {

 91         printf("init_bitmap failed\n");

 92         return -1;

 93     }

 94 

 95     if(!in_process(in, size, bitmap))

 96     {

 97         printf("in_process failed\n");

 98         fclose(in);

 99         free(bitmap);

100         return -1;

101     }

102     

103     if(!out_process(out, size, bitmap))

104     {

105         printf("in_process failed\n");

106         fclose(in);

107         fclose(out);

108         free(bitmap);

109         return -1;

110     }

111     

112     fclose(in);

113     fclose(out);

114     free(bitmap);

115     return 0;

116     

117 }

测试数据产生文件:

View Code
 1 #include<stdio.h>

 2 #include<stdlib.h>

 3 #include <assert.h>

 4 //产生[lower upper]区间的随机整数

 5 int randint(int lower, int upper)

 6 {

 7     assert(lower <= upper);

 8     return rand()%(upper - lower + 1) + lower;

 9 }

10 

11 //交换set[lower - 1] 与 set [upper]

12 void swap(unsigned int *set, unsigned int x, int y )

13 {

14     unsigned int element;

15     element = set[x - 1];

16     set[x - 1 ] = set[y - 1];

17     set[y - 1] = element;

18 }

19 

20 //函数调用需要三个参数: 数据的最大值 数据数目 输出文件

21 int main(int argc, char *argv[])

22 {

23 

24     unsigned int *set;

25     FILE *file;

26     int i;

27     if(argc != 4)

28     {

29         printf("Usage: %s max size infile outfile\n", argv[0]);

30         return -1;

31     }

32     

33     unsigned int max = atoi(argv[1]);

34     unsigned int size = atoi(argv[2]);

35     

36     assert(size < max);

37     

38     if((file = fopen(argv[3], "w")) == NULL)

39     {

40         printf("open infile failed\n");

41         fclose(file);

42         return -1;

43     }

44     

45     set = (unsigned int *)malloc(max * sizeof(unsigned int));

46     

47     if(set == NULL)

48     {

49         printf("Failed to malloc set\n");

50         fclose(file);

51         return -1;

52     }

53     

54     for(i = 1; i <= max; i ++)    

55         set[i - 1] = i;

56     

57     //产生size个[1, max]内不重复的整数,源自编程珠玑第一章习题4

58     for(i = 1; i <= size; i ++)

59     {

60         swap(set, i, randint(i, max));

61         

62         if(feof(file))//检测文件结束

63         {

64             printf("when output data into  flie, some errors happened!\n");

65             return 1;

66         }

67         else

68         {

69             printf("data[%u] = %u\n", i, set[i - 1]);

70             fprintf(file, "%u ", set[i - 1]);

71         }

72         

73     }

74     

75     fclose(file);

76     free(set);

77     return 0;

78     

79 }

你可能感兴趣的:(排序算法)