编程珠玑(1)

《编程珠玑》(第二版)(一)开篇

引言部分:

编程珠玑作为计算机科学领域的经典书籍,通过围绕程序设计人员面对的一系列实际问题展开内容,书中一些精心设计的有趣而又颇具指导意义的程序,对实用程序需设计技巧及基本设计原则的描述,为复杂问题的求解进行了睿智的描述,对各个层次的程序员都具有参考价值。

1.磁盘文件排序问题

A.问题背景

开篇文章中,通过某程序员与作者之间的谈话展开,接下来就称这个程序员为小白吧,小白询问了作者关于如何对于一个磁盘文件进行排序的问题,作者通过与小白的交流获取了如下信息:

(1)为什么不用系统提供的功能排序,而是非要自己编写排序程序呢?

    答:由于需要,现在在一个大系统中排序,由于不明的技术原因,不能使用系统中的文件排序功能。(好吧,是够zz的)

  (2) 需要排序的内容是多少?文件有多少天记录?每条记录的格式是多少?

   答:文件最多包含包含一千万条记录,每条记录都是7位的整数

     追问:既然文件这么小,为什么不直接在内存里进行排序,而是非要在磁盘里进行排序呢?

   答:尽管机器里有许多兆字节的内存,但排序功能只是大系统的一部分,所以,到时估计只有1MB的内容可以用

(3)其他信息?

  答:每条记录都是7位整数,再无其他数据,每个数据最多出现一次

具体问题:

              小白在开发数据库处理系统的过程中,需要排序的整数就是免费电话号码,输入文件就是电话号码的列表(已删除其他信息),号码重复出错就是出错

期望的输出文件是以升序排列的电话列表,应用背景同时定义了相应的功能需求。当与系统的会话时间比较长时,用户大约每小时请求一次有序文件,并且在排序完成之前什么都

干不了,因此排序最多只执行几分钟,10秒钟是比较理想的运行时间

B.准确的问题描述(不要强求不可知,要由已知推未知,根据需求建立问题)

输入:一个最多包含n个正整数的文件,每个数都小于n,其中n=10^7,如果在输入文件中有任何整数重复出现就是致命错误,没有其他数据与该整数相关联。


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


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


C.解决方案分析

(1)归并排序

分析:通过调整归并排序,由于是对整数排序,因此可以使程序由原来的200行减少到几十行,运行速度会加快,但是完成程序并使之运行仍然需要几天时间

(2)利用问题的特殊性

如果每个号码都使用7个字节来存储,那么在可用的1MB的存储空间里大约可以存143000个号码(1024*1024/7),如果每个号码都使用32位整数来表示,在1MB的存储空间里就可以存储

250000个号码,因此可以遍历输入文件40趟来完成排序,在第一趟遍历中,将0至249999之间的任何整数都读入内存,并对这250000个整数进行排序,然后写到输出文件中,第二趟

遍历排序就是从250000至499999之间的整数,依次类推,到了第40趟的时候即是对9750000至9999999之间的整数进行排序,对于内存而言适合使用快速排序提高效率,而且仅仅需要20行代码

,于是整个程序就可以在一两页纸内实现,该程序拥有所期望的特性,不必使用中间磁盘文件,但是代价是要读取输入文件40次。

图1:归并排序:读入输入文件一次,然后在工作文件帮助下完成排序并写入输出文件一次,工作文件需要多次读写

图2:40趟算法读入输入文件多次,写输出文件仅一次,不使用中间文件。

图3:下面方案结合上述两种方法的优点,读输入文件一次,且不使用中间文件


只有在输入文件中所有整数都可以在可用的1MB内存中表示的时候才能够实现该方案,于是问题就归结为用大约800万个可用为来表示最多1000万个互异的整数。

考虑一种合适的方式.

D.实现概要

(1)通过位图(bitmap)或位向量来表示集合,可用一个20位长的字符串来表示一个所有元素小于20的简单的非负数整数集合,

举个例子说明下:好比某集合:{1,2,3,5,8,13}:0 1 1 1 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0

代表集合中的数据都设置为1,其他的位置都设置为0。

(2)通过(1)中位图的思想,若给定表示文件中整数集合的位图数据结构,则可以分为三个自然阶段来编写程序,其中n为位向量中的位数(在本例中为10,000,000)伪代码如下

step1:.将所有的位都置为0,从而将集合初始化为空

/******initialize set to empty*****/
  for i=[0,n)
       bit[i]=0 
step2:通过读入文件中的每个整数来建立集合,将每个对应位都置为1。

/******insert present elements into the set****/
for each i in the input file 
             bit[i]=1
step3:检验每一位如果该位为1,就输出对应的整数,由此产生有序的输出文件。
/******write sorted output****/
for i=[0,n)
 if bit[i]==1
       write i on the output file

注:for i=[0,n)表示从0到n-1的范围内对i进行迭代

2.位图数据结构

(1)定义

位图数据结构,就是用一块内存区域的每个比特表示一个对象的数据结构。

叫做 bitmap 或者 bitplane。

优点是速度快,内存空间占用小,能表示大范围的数据。

A bitset stores bits (elements with only two possible values: 0 or 1,true orfalse, ...).

The class emulates an array of bool elements, but optimized for space allocation: generally, each element occupies only one bit (which, on most systems, is eight times less than the smallest elemental type:char).

Each bit position can be accessed individually: for example, for a given bitset namedfoo, the expressionfoo[3] accesses its fourth bit, just like a regular array accesses its elements. But because no elemental type is a single bit in most C++ environments, the individual elements are accessed as special references type (http://www.cplusplus.com/reference/bitset/bitset/)


(2)适用范围

 位图数据结构在排序算法中的特殊应用是利用排序问题中不常见的三个属性:

第一输入数据限制在相对较小的范围内 (这也是编写软件时最多的设计方法);

第二数据没有重复;

第三对于每条记录而言,除了单一数据外(此题为单一的整数),没有任何其他关联数据。

从而达到写算法时能根据实际问题实现最有效的时间─空间折中与双赢。


(3)位图数据结构的实现

(a)比特的编号机制

下面过一个示例来帮助大家理解比特的编号方法,在这里,从低字节的低位比特位开始,第一个bit为0,最后一个bit为 n-1(大端模式

现有数组为int a[3],因此a[0]对应的bit位0-31,a[1]对应32-63,a[2]对应64-95

#include<iostream>

using namespace std;

int main(int argc,char *argv)
{
	int a[3];
	for(int i=0;i<=3;i++)
	{
		a[i]=1;
		
	}
	for(int i=0;i<3;i++)
	{
		a[i]=a[i]<<5;                 //左移5位
		cout<<a[i]<<endl;
	}
	return 0;
}
输出结果如下图所示

由此可知原来数据存放如下

00000000000000000000000000000000
经过经过位运算后,也即左移5位后为,即对应的数为32

00000000000000000000000000100000
(b)位图实现

见http://blog.csdn.net/smfwuxiao/article/details/7161761

持续更新中...

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值