这一章通过一次对话引出来,对话的请教者向作者请教了一个有关于美国电话排序的问题,每个美国电话由3位“区号”,(当时只有800这一个免费的区号),后再跟7位数字,问题的具体描述是:

 输入:一个最多包含n个正整数的文件,每个数都小于n,其中n=10*10*...10(共7个10相乘),(注:很抱歉,博客里面不支持mathType里面的数据格式)

            如果在输入文件中有任何整数重复出现就是致命错误,没有其他数据与该整数相关联。

 输出:按升序排序的输入整数的列表

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


解决方法:

1. 一般的方法,

         以一般的基于磁盘的归并排序程序为起点,对其调整,可将原来的程序减少为几十行,同时使程序运行得更快,但完成运行可能仍然需要几天时间。

2. 利用该问题的特殊性。

         若每个号码使用7个字节存储,可在1M存储空间里大约存143 000个号码,

         若每个号码使用32位(4个字节)整数来表示,可在1M存储空间存250 000个号码,需遍历文件40趟。

               第一趟:0~249 999之间任何号码, 先读入内存,排完序后写到输出文件中。

               第二趟:250 000~499 999之间的整数。。。。。。。。

               。。。。。。。

         内存排序,仅需20行代码,该程序的特性是不必考虑中间磁盘文件,但是代价是读取输入文件40次。

3. 神奇的算法

         使用位图或位向量的集合。可用一个20位长的字符串来表示一个所有元素都小于20的简单的非负整数集合,

          如:可用字符串来表示集合{1,2,3,5,8,13}:01110100100001000000   代表集合中数值的位置1,其他位置0

     实际问题,每个7位十进制正数表示一个小于1 000万的整数,使用一个具有1 000万个位的字符串来表示这个文件,其中,当且仅当整数 i 在文件中存在时,第 i 

     位为1,。这种表示利用了该问题的三个在排序问题中不常见的属性:输入数据限制在相对较小的范围内;数据没有重复;而且对于每条记录而言,除了单一整数外,没有任何其他关联数据。

           若给定表示文件中整数集合的位图数据结构,则可以分三个自然阶段来编写。第一阶段,将所有位都置0,从而将集合初始化为空;第二阶段,通过读入文件      中的每个整数来建立集合,将每个对应的位都置为1;第三阶段,如果该位为1,就输出对应的整数,由此产生有序的输出文件。令n为位向量中的位数(本例为10 000 000),程序伪代码表述如下:

      //phase 1: initialize set to empty

        for i=[0,n)

          bit[i]=0;

      //phase 2: insert parent elements into the set 

        for each i in the put file 

            bit[i]=1;

      //phase 3:write sorted output

         for i=[0,n]

            if bit[i] == 1

                 write i on the output file


结论:对细小问题的仔细分析有时可以得到明显的实际益处

        (1)正确的问题,明确问题。

        (2)位图的数据结构

        (3)多趟算法

        (4)时间与空间的折中与双赢

        (5)简单的设计

 

这一章的这个问题,作者根据实际问题进行细致的分析,最后得到使用位操作来进行处理,相当的巧妙,该方法不但简化了程序,提高了运行速度,也容易实现。

高人,呵呵,以后也要学会使用位来解决某些问题。

posted on 2010-11-08 17:33  Blanche  阅读(2253)  评论(11编辑  收藏  举报