zoukankan      html  css  js  c++  java
  • 编程珠玑 第一章 位图排序算法

    位图排序是一种效率极高(复杂度可达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 }
  • 相关阅读:
    项目实战:Qt+Android模拟操作器(模拟操作app,打开,点击,输入,获取验证码等等)
    项目实战:流水线图像显示控件(列刷新、1ms一次、缩放、拽拖、拽拖预览、性能优化、支持OpenGL GPU加速)
    OpenCV开发笔记(七十三):红胖子8分钟带你使用opencv+dnn+yolov3识别物体
    Oracle数据库由dataguard备库引起的log file sync等待
    使用udev高效、动态的管理Linux设备文件
    Linux配置和管理设备映射多路径multipath
    ELK6环境搭建
    存储系列1-openfiler开源存储管理平台实践
    redhat / centos开启关闭防火墙
    教你如何使用github+jsDelivr搭建免费图床
  • 原文地址:https://www.cnblogs.com/bigrabbit/p/2657495.html
Copyright © 2011-2022 走看看