读书日记·编程珠玑·第一章

前言

最近在慢慢地读《编程珠玑》这本书,里面的算法比较巧妙、有趣。读的过程中,也是希望自己做一些笔记,一方面帮助自己理解,另一方面可以日后可以快速回顾。也写了一些代码来实现算法,第一章的代码可见github

直奔问题

书中第一章是讲的这么一个问题:

输入:一个最多包含n正整数的文件,每个数都小于n,其中n为10^7。并且文件中的整数不会有重复。
输出:按照升序排列的输出这些整数。
约束:最多有(大约有)1 MB的内存空间可用,有充足的磁盘空间可用。

我们可以分析出来,这是一个排序问题,内存空间有限。所以一次把数字读到内存中再使用排序算法进行排序行不通啊,得另寻它法。

书中首先提到了两种方法:

  1. 多趟排序算法。
  2. 基于磁盘文件的归并排序。

以及书后面提到的最优解法,称为位图法。下面容我对这些解决办法徐徐道来。

解决问题

1. 多趟排序算法

在解决问题前,我们首先要做的是理解问题,之后才能想良策啊。

这里因为问题具有一定的特殊性,即它们是不重复的整数,并且最大值为n。每个整数占空间32bit,那么1 MB可以容纳250 000个整数,于是我们可以分40趟来遍历文件中的数字进行排序:

  1. 遍历文件排序0至249 000的数字,并写入文件。
  2. 遍历文件排序249 000至499 999的数字,并写入文件。
    ......

依次下去,即可对文件中的数字全部进行排序。

2. 基于磁盘文件的归并排序

归并排序我们都十分熟悉,其用到了分而治之的思想。我们先来熟悉一下它,主要分为了两个过程:

  1. 一直拆分下去,直到无法拆分为止。到最后只剩一个元素,只有一个元素当然是有序的。
  2. 再对有序的分组二对二的进行往回归并,其归并的过程也十分简单。我们转移到[1,7],[0,2,6]归并那一处,其归并过程如下:

0<1 则 0
1<2 则 0,1
2<7 则 0,1,2
6<7 则 0,1,2,6
最后还剩7 则0,1,2,6,7

图解归并排序过程

哎,上面全是大白话。。。结合图片进行理解哈,问题不大,嘻嘻。回忆完归并排序,我们就进入正题——基于磁盘的归并排序。

我们需要对10^7个不重复的数字进行排序。每个数字占32位,于是1 MB的内存可以存储250000个数字。可以见下图,phoneNumber.txt文件正是存储的待排序的数字。

  1. 分四十次,每次从phoneNumber.txt文件中读取250000个数字进行排序,并写入到文件phoneNumber_sort_round1_*.txt文件中。
  2. phoneNumber_sort_round1_0.txtphoneNumber_sort_round1_1.txt进行归并排序。进行归并排序时,首先向两个文件中各读取一个数字,进行比较并将小的数字写入phoneNumber_sort_round2_0.txt,依次进行下去,最终两个文件会汇合为phoneNumber_sort_round2_0.txt。按照同样的方法,可以生成phoneNumber_sort_round2_*.txt
  3. 同样以步骤2的方法,最后文件会汇合到一个文件phoneNumber_sorted.txt,该文件就是最终的排序结果。
基于磁盘的文件归并排序

位图法

虽然前面的两种方法,都可以达到我们的目标。可是,需要多次对文件进行IO。可见,其并不优秀啊。我们需要一个解决方案,不但能节约内存空间,也能提升排序的时间。

所谓的位图法,我们可以用一个小小例子来进行说明。假设我们现在需要对7,5,2,3,4,0这一串数字进行排序,那么首先申请8 bit的空间,其中其初始状态为:

|--0--|--0--|--0--|--0--|--0--|--0--|--0--|--0--|

第0位即代表数值0, 第1位即代表数值1,第n位即代表数值n......
当bit位为0时,那么表示没有相关的数值;当bit位为1时,代表有相关的数值。

遍历7,5,2,3,4,0,依次将相应的bit位设置为1:

|--1--|--0--|--1--|--1--|--1--|--1--|--0--|--1--|

最后,遍历bit数组,根据第n位即代表数值n,以及1代表有数值的规约,即可输出最后的排序结果:023457

总结以上排序的步骤:

  1. 申请大小合适的bit数组。
  2. 遍历待排序数组,将相应bit位设置为1.
  3. 遍历bit数组,即可输出最后的排序结果。

可见该方法排序十分高效,可是需要满足的条件是:待排序数组为整数,并且并其中没有重复数字!

补充问题

除了开篇提到的问题之外,书中也补充到了一个问题。

如果那个程序员说的不是每个整数最多出现一次,而是每个整数最多出现10次,那么又该如何解决这个问题呢。

我们只需要调整一下位图法即可解决这个问题,前面的问题我们是第n位即代表数值n。在这里就是每4bit代表一个数值,如下:

|--0--|--0--|--0--|--0--|   |--0--|--0--|--1--|--0--|   |--1--|--0--|--1--|--0--|

上面即代表,数值0未出现,数值1出现了2次,数值2出现了10次。

只要我们按在这个规则来设置结构,最后也可完成排序。

总结

解决问题之前,我们必须得非常熟悉问题,这样才能帮助我们找到最合适的解决方法。另一方面,任何事情没有绝对的一面:这里我们看到了,不一定都是牺牲空间换取时间,或者牺牲时间换取空间。

好把,就介样了,See you !

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容