《编程珠玑(第2版•修订版)》—第2章2.8节变位词程序的实现(边栏)

2.8 变位词程序的实现(边栏)⑪ 
我的变位词程序按三个阶段的“管道”组织,其中一个程序的输出文件作为下一个程序的输入文件。第一个程序标识单词,第二个程序排序标识后的文件,而第三个程序将这些单词压缩为每个变位词类一行的形式。下面是一个仅有6个单词的字典的处理过程。

输出包括三个变位词类。

下面的C语言sign程序假定没有超过100个字母的单词,并且输入文件仅包含小写字母和换行符。(因此我使用了一个一行的命令对字典进行预处理,将其中的大写字母改为小写字母。)

int charcomp(char *x, char *y) { return *x - *y;}

#define WORDMAX 100
int main(void)
{   char word[WORDMAX], sig[WORDMAX];
    while (scanf("%s", word) !=EOF) {
        strcpy(sig, word);
        qsort(sig, strlen(sig), sizeof(char), charcomp);
        printf("%s %s\n", sig, word);
    }
    return 0;
}

while循环每次读取一个字符串到word中,直至文件末尾为止。strcpy函数复制输入单词到单词sig中,然后调用C标准库函数qsort对单词sig中的字母进行排序(参数是待排序的数组、数组的长度、每个待排序项的字节数以及比较两个项的函数名。在本例中,待比较项为单词中的字母)。最后,printf语句依次打印标识、单词本身和换行符。

系统sort程序将所有具有相同标识的单词归拢到一起。squash程序在同一行中将其打印出来。

int main(void)
{  char word[WORDMAX], sig[WORDMAX], oldsig[WORDMAX];
   int linenum = 0;
   strcpy(oldsig, "");
   while (scanf("%s %s", sig, word) != EOF) {
       if (strcmp(oldsig, sig) !=0 && linenum >0)
          printf("\n");
       strcpy(oldsig, sig);
       linenum++;
       printf("%s ", word);
   }
   printf("\n");
   return 0;
}

大部分工作都是使用第二个printf语句来完成的。对每一个输入行,该语句输出第二个字段,后面跟一个空格。if语句捕捉标识之间的差异。如果sig与oldsig(其上一次的值)不同,那么就打印换行符(文件中的第一条记录除外)。最后一个printf输出最后一个换行符。

在使用小输入文件对这些简单部分进行测试后,我通过下面的命令构建了变位词列表:

sign < dictionary | sort | squash >gramlist
该命令将文件dictionary输入到程序sign,连接sign的输出至sort,连接sort的输出至squash,并将squash的输出写入文件gramlist。程序的运行时间为18秒:sign用时4秒、sort用时11秒而squash用时3秒。

我在一个包含230 000个单词的字典上运行了该程序。然而,不包括众多的-s和-ed后缀。以下是一些很有趣的变位词类。

subessential suitableness
canter creant cretan nectar recant tanrec trance
caret carte cater crate creat creta react recta trace
destain instead sainted satined
adroitly dilatory idolatry
least setal slate stale steal stela tales
reins resin rinse risen serin siren
constitutionalism misconstitutional
① Martin Gardner(1914—),美国著名的科普作家,主持《科学美国人》的数学游戏专栏25年,写作了大量文章和图书,有世界影响。——编者注

②即循环移位。——审校者注

③Doug McIlroy(1932—),著名计算机科学家,美国工程院院士,现为达特茅斯学院兼职教授。他于1968年第一个提出了软件组件的概念。他参与设计了PL/I和C++语言、Multics和Unix操作系统。Unix上许多工具是他开发的,包括diff、echo、sort、spell和join等,管道实现也由他首创。他曾长期担任贝尔实验室计算技术研究部主任,并曾任ACM图灵奖主席。——编者注

④Brian Kernighan(1942—)著名计算机科学家,现为普林斯顿大学教授。他与人合作创造了Awk和AMPL编程语言,对Unix和C语言的设计也有很大贡献。他还与人合写了多部计算机名著,包括与Ritchie合著的The C Programming Language。——编者注

⑤P. J. Plauger,著名C/C++语言专家,现为著名标准库开发商Dinkumware总裁。他曾担任ISO C标准委员会负责人,著有名著《C标准库》(中文版由人民邮电出版社出版)。——编者注

⑥Ken Thompson(1943—),著名计算机科学家,1983年图灵奖得主。现为Google杰出工程师。他是Unix操作系统的主要设计者,并设计了C语言的前身B语言。——编者注

⑦该变位词算法是由许多人各自独立发现的,至少可以追溯到20世纪60年代中期。

⑧Don Knuth(1938—),中文名高德纳,著名计算机科学家,斯坦福大学荣休教授。因对算法分析和编程语言设计领域的贡献获1974年图灵奖。他是名著The Art of Computer Programming的作者,设计了TEX排版系统。——编者注

⑨该书第2版英文影印版已由清华大学出版社引进出版,中文书名《计算机程序设计艺术 第3卷 排序和查找》,中译版已由国防工业出版社出版,中文书名《计算机程序设计艺术 第3卷 排序与查找》。——编者注

⑩Mike Lesk,著名程序员,ACM会士,美国工程院院士,现任Rutgers大学教授兼系主任。他在贝尔实验室工作期间开发了大量工具,包括lex、uucp和stdio.h的前身。他领导了美国NSF数字图书馆计划,该计划支持了斯坦福大学搜索引擎研究项目,促生了Google。——编者注

⑪边栏在杂志的文章中是处在正文之外的,通常是页边上的一列。它们本质上不是专栏的一部分,仅仅提供了关于材料的一些观点。在本书中,它们作为每章的最后一节出现,用“(边栏)”来标记。

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

时间: 2024-10-02 01:51:48

《编程珠玑(第2版•修订版)》—第2章2.8节变位词程序的实现(边栏)的相关文章

《Ruby程序员修炼之道》(第2版)—第1章1.3节Ruby扩展和编程库

1.3 Ruby扩展和编程库本节的要点并不是关于Ruby标准库的参考.曾在引言中解释过,本书的目标不是编写一本Ruby语言的参考文档,而是教会读者使用Ruby语言并掌握它,并最终拓宽视野. 相应地,本节的目标是讲述扩展的工作方式,即如何使用Ruby运行这些扩展.它们之间技术实现的不同,并最终能让用户自己编写扩展和库文件的扩展架构. 随Ruby发布的扩展通常全部作为标准库来引用.标准库包括为不同项目和任务所提供的扩展,如数据库管理.网络.数学领域.XML处理等.标准库精密的结构每次改变,哪怕只有一

《Ruby程序员修炼之道》(第2版)—第1章1.1节进入Ruby的世界

第1章 进入Ruby的世界 Ruby程序员修炼之道(第2版) 本章主要内容 Ruby语法的生存工具箱① Ruby基础编程指引:程序编写.保存.运行和错误检查 Ruby安装指南 Ruby的扩展机制 Ruby中易用的命令行工具,包括交互式Ruby解释器(irb) 本书的内容是Ruby基础,而本章是基础中的基石.本章的目标是让读者在开始学习Ruby之前掌握足够的知识和技巧. 接下来读者将看到Ruby的基本语法和技术,以及Ruby的运行机制:如何写一个程序,怎样使用Ruby运行程序,以及如何把一个程序分

《Ruby程序员修炼之道》(第2版)—第1章1.4节易用的Ruby工具和应用程序

1.4 易用的Ruby工具和应用程序 安装Ruby后,就可以得到一组重要的命令行工具,它们被安装在配置信息bindir所指定的文件夹中,通常是/usr/local/bin./usr/bin或者/opt同等的目录中.(可以使用require "rbconfig"去测试一下RbConfig::CONFIG["bindir"]返回的结果.)这些命令行工具具体是以下几个. ruby:解释器. irb:Ruby交互式解释器. - rdoc和ri:Ruby文档工具. rake:

《Ruby程序员修炼之道》(第2版)—第1章1.2节剖析Ruby的安装

1.2 剖析Ruby的安装在系统上安装Ruby意味着在许多磁盘目录中安装了Ruby语言的库和支持文件.大多数时候,Ruby都知道如何找到其所需要的这些目录而不用弹出提示.但是了解Ruby安装的知识对了解Ruby本身大有益处. 查看Ruby的源代码 除了Ruby安装目录体系之外,Ruby的源代码目录也安装好了.如果没有,可以到Ruby的主页中下载.源代码目录中包含了许多在最终安装中出现的Ruby文件和许多已编译为目标文件并安装好的C语言文件.另外,源代码目录包含了一些如ChangeLog和软件授权

《软件测试技术大全:测试基础 流行工具 项目实战(第3版)》—第1章1.6节模拟面试问答

1.6 模拟面试问答 本章介绍的是软件测试相关的背景,以及软件测试的发展情况等.身为软件测试员,应该或多或少地了解软件测试的发展动态,及其相关的历史事件等内容,这样无论是在与同行交流,向开发人员介绍和讲解测试,还是在应聘面试中,都会有更多的话题. 一般在应聘过程中,面试官可能会问到以下一些问题,读者可以根据自己的了解以及在本章中学到的内容做出相应的回答. (1)您觉得目前的软件测试行业的现状是怎样的? 参考答案:目前的软件测试行业在国内正在蓬勃地发展中,但是由于起步比较晚,虽然大部分公司都已经设

《C++入门经典(第5版•修订版)》——6.8 作业

6.8 作业 C++入门经典(第5版•修订版)本章介绍了一些复杂的程序流程,您现在应该能够回答几个问题并完成两个练习,以巩固这方面的知识. 6.8.1 测验 1.在for语句中应使用哪种数据类型? A.整型 B.整型或浮点数 C.任何数据类型都可以 2.哪种循环不能使用break或continue语句? A.for B.for和while C.无 3.在switch语句中,break命令有何作用? A.跳到下一个case B.结束switch语句 C.跳到default部分 6.8.2 答案 1

编程珠玑--旋转算法

旋转算法出自<编程珠玑>第二章题目.   <编程珠玑>一书对算法是极度推崇,这点意识在我们看书的时候每每都有被灌输.使用一种好的算法往往能使得程序更加漂亮,也很能带给我们程序员某种满足感.   题目:将一个n元一维数组a[n]左移i个位置.例如,当n=8,i=3时,数组abcdefgh旋转为defghabc.请设计一个算法完成这个任务.   1. 块交换法: 分析:将n元一维数组a[n]分解为两块,将第一块存储在临时数组中,将第二块前移i个单位,再将临时数组加入到第二块后面.  

编程珠玑--粗略估算

粗略估算是<编程珠玑>中第七章提到的内容.   这篇文章将"粗略估算"看做是一项工程技术,是程序员必备的一项技能之一. 本人非常同意这个观点.粗略估算是一种把复杂的事情简单化的能力.我们对某个算法的时间复杂度和空间复杂度的估算就是基于这种估算的能力.如果你能较为准确的估算出一个程序的输出结果,如果你能准确估算出这个程序的运行时间,如果你能准确估算出这个项目的开发时间--如果你能拥有这样的能力,该有多么美好啊.所以难怪乎像微软.Google这样的大公司老喜欢出"请计

编程珠玑--位图法排序

题目:一个最多包含n个正整数的文件,每个数都小于n,其中n=10^7,且所有正整数都不重复.求如何将这n个正整数升序排列. 约束:最多有1MB的内存空间可用,有充足的磁盘存储空间.   分析:这个题目的最大亮点是只有1MB的内存空间,我们可以通过计算得出,内存只有1MB可以储存的int(4byte)有10^3*10^3/4=250 000个号码.而包含正整数的文件约为10^7个int大小.这意味着无法将所有文件中的正整数一次读取进入到内存空间中去进行排序算法.因此衍生出下面两种方法:   方法1