zoukankan      html  css  js  c++  java
  • 《编程珠玑》中“位图排序”引发的一系列实验

    问题:

    一个文件有8*106个正整数,每个数都小于107。文件中所有整数都是唯一的。要求对这些整数排序,按升序把排序的结构输出到磁盘上。

    解决问题的方案有很多,下面我们介绍几种典型的方案。

    1、高效的“位图排序”

    特殊要求:最多有大约1M的内存空间可用!

    如果在这个限制下,快速的对这些整数进行排序,一个优秀的解决方案是使用“位图排序”。

    位图排序的思想就是在内存中申请一块连续的空间作为位图,初始时将位图的每一位都置为0。然后依次读取待排序的整数,将整数对应的位设置为1。最后按顺序扫描位图,如果某一位为1,输出到已排序文件。

    比如待排序的数据S={3,0,4,1,7,2,5},最大为7,我们可以设置一个八位的位图B,将位图的每一位初始为0。对S中的每一个整数d,设置B[d]=1,即B=[1,1,1,1,1,1,0,1],最后扫描位图,对位图的每一位i,如果B[i]==1,则输出i到已排序文件,排序后的S={0,1,2,3,4,5,7}。

    整个过程只需要遍历一遍待排序文件和位图,时间复杂度O(n),需要的辅助空间为(max(S)/8)字节。

    程序代码:

    bitmap_sort.c

    #include <stdio.h>
    #include "data_size.h"
    
    #define SHIFT 5
    #define MASK 0x1F
    
    int a[1+MAX_DATA/32];
    
    void set(int i)
    {
        a[i>>SHIFT] |=1<<(i& MASK );
    }
    
    int test(int i)
    {
        return a[i>>SHIFT] & (1<<(i& MASK ));
    }
    
    int main(int argc,char** argv)
    {
        int i=0;
        FILE *fin=NULL,*fout=NULL;
        for(i=0;i<1+MAX_DATA/32;i++)
            a[i]=0;
    
        if((fin=fopen(argv[1],"r"))==NULL)
        {
            printf("error!
    ");
            return 1;
        }
        while(fscanf(fin,"%d",&i)!=EOF)
            set(i);
        
        if((fout=fopen(argv[2],"w"))==NULL)
        {
            printf("error!
    ");
            return 1;
        }
        for(i=0;i<MAX_DATA;i++)
            if(test(i))
                fprintf(fout,"%d
    ",i);
        fclose(fin);
        fclose(fout);
        return 0;
    }

    data_size.h

    #ifndef DATA_SIZE_H_
    #define DATA_SIZE_H_
    
    #define SIZE 8000000
    #define MAX_DATA 10000000
    
    #endif

    生产待排序文件数据的程序见附录。

    测试(用time命令统计运行时间):(2次)

    编译之后的可执行程序:bitmapsort  待排序文件:data.txt  输出文件:data2.txt

    注:linux的time统计程序的运行时间,其统计结果包含以下数据:
    1)实际时间(real time): 从command命令行开始执行到运行终止的消逝时间;
    2)用户CPU时间(user CPU time): 命令执行完成花费的用户CPU时间,即命令在用户态中执行时间总和;
    3)系统CPU时间(system CPU time): 命令执行完成花费的系统CPU时间,即命令在核心态中执行时间总和

    2、linux排序命令

    $ time sort -n -o data3.txt data.txt

    使用linux的sort命令进行排序。

    -n  :使用“纯数字”进行排序(默认是以文字型态来排序的);

    -o : 把排序结果输出到文件,而不是控制台

    测试:(2次测试)

    待排序文件:data.txt  输出文件:data3.txt

    3、C标准库的qsort()函数

    qsort包含在<stdlib.h>头文件中,此函数根据你给的比较条件进行快速排序,通过指针移动实现排序。排序之后的结果仍然放在原数组中。使用qsort函数必须自己写一个比较函数。

    函数原型:

    void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );

    base :数组起始地址
    num:数组元素个数
    siz:每一个元素的大小
    comparator:函数指针,指向比较函数

    qsort.c

    #include <stdio.h>
    #include <stdlib.h>
    #include "data_size.h"
    
    int intcomp(const void *x, const void *y)
    {
        return *(int *)x-*(int *)y;
    }
    
    int a[SIZE];
    
    int main(int argc, char** argv)
    {
        FILE *fin=NULL,*fout=NULL;
        if((fin=fopen(argv[1],"r"))==NULL)
        {
            printf("open file error!
    ");
            return 1;
        } 
        int i=0;
        while(fscanf(fin,"%d",&a[i])!=EOF)
            i++;
        qsort(a,SIZE,sizeof(int),intcomp);
    
        if((fout=fopen(argv[2],"w"))==NULL)
        {
            printf("open file error!
    ");
            return 1;
        }
        for(i=0;i<SIZE;i++)
            fprintf(fout,"%d
    ",a[i]);
        return 0; 
    }

    测试:(2次)

    编译之后的可执行程序:qsort  待排序文件:data.txt  输出文件:data4.txt

    4、C++标准库中set容器来进行排序

    因为待排序的整数都是唯一的,并且set容器内部会按照一定的顺序组织内部的数据。我们可以用set容器来进行排序。

    set_sort.cpp

    #include <iostream>
    #include <fstream>
    #include <set>
    using namespace std;
    
    int main(int argc,char **argv)
    {
        int i=0,n=0;
        set<int> s;
        set<int>::iterator it;
        ifstream in(argv[1]);
        if(!in.is_open())
        {
            cout<<"error"<<endl;
            return 1;
        }
        while(!in.eof())
        {
            in>>n;
            s.insert(n);
        }
    
        ofstream out(argv[2]);
        if(!out.is_open())
        {
            cout<<"error"<<endl;
            return 1;
        }
        for(it=s.begin();it!=s.end();++it)
        {
            out<<*it<<endl;
        }
    
        in.close();
        out.close();
        return 0;
    }

    测试:

    编译之后的可执行程序:set_sort  待排序文件:data.txt  输出文件:data5.txt

    总结

    上面四个程序的排序结果都正确,已用diff命令对比过。

    从上面的运行时间,我们可以看出:

    位图排序、C标准库qsort(排序)、系统命令排序、C++标准库set容器排序,它们的排序运行时间依次增高。

    在特殊要求“最多有大约1M的内存空间可用!”的情况下,位图排序是一个非常优秀的排序方法,其运行速度快且占用内存小,但是前提是,待排序的数据都是整数,且不存在重复。

    附录:

    生产包含8*106个正整数 且 每个数都小于107的排序文件。

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include "data_size.h"
    
    int a[MAX_DATA];
    
    void swap(int i,int j)
    {
        int temp=a[j];
        a[j]=a[i];
        a[i]=temp;
    }
    
    int main(int argc, char **argv)
    {
        int i=0;
        printf("%x
    ",RAND_MAX);
        printf("%ld
    ",time(NULL));
        srand(time(NULL));
    
        for(i=0;i<MAX_DATA;i++)
        {
            a[i]=i;
        }
    
        for(i=0;i<SIZE;i++)
        {
            int j=rand()%MAX_DATA;
            swap(i,j);
        }
    
        FILE * fin=NULL;
        if((fin=fopen(argv[1],"w"))==NULL)
        {
            printf("error!
    ");
            return 1;
        }
    
        for(i=0;i<SIZE;i++)
        {
            fprintf(fin,"%d
    ",a[i]);
        }
        fclose(fin);
        
        printf("success!
    ");
        return 0;
    }
  • 相关阅读:
    概念
    Jquery和Aspnet前台控件及后台代码交互
    未能找到引用的组件“Microsoft.Office.Core
    C#操作Excel,调用ApplicationClass.Quit()关闭Excel时,发生异常:Microsoft Office Word 遇到问题需要关闭
    Javasrcipt捕获按键
    使用Interop.Excel生成Excel
    Javasrcipt时间相关函数
    (转)各种纹理贴图技术
    (转)立体纹理
    (转)地形碰撞高度计算
  • 原文地址:https://www.cnblogs.com/windlaughing/p/3354615.html
Copyright © 2011-2022 走看看