算法精粹:经典计算机科学问题的Java实现
上QQ阅读APP看书,第一时间看更新

Preface 前言

20年来,Java已经成为世界上非常流行的编程语言之一。可以说,它已经成为企业、高等教育以及Android应用程序开发中的主导语言。通过本书,我希望能够引领大家意识到Java不仅仅是实现最终目标的一种手段,还是解决计算问题的一种工具。本书中的问题能够帮助老练的程序员在学习某些编程语言高级特性的同时,反思之前学过的计算机科学课程内容并有新的收获。使用Java的在校生和自学型程序员都可以通过学习普遍适用的问题求解技术来加速计算机科学课程的学习进度。本书涵盖了各种各样的问题,因此所有人都能从中受益。

本书不是Java的一般性介绍书籍,因此不适合Java新手阅读,而是面向中高级Java程序员。虽然本书使用的是Java 11中的特性,但并不需要你精通该版本的所有内容。

如果说计算机之于计算机科学就像望远镜之于天文学,那么编程语言就像望远镜的镜头。总之,经典计算机科学问题在这里表示“通常在本科计算机科学课程中教授的编程问题”。无论是在本科的课堂(计算机科学、软件工程等)上,还是在中级编程课本(例如,关于人工智能或算法的入门书)中,有些交给新手程序员解决的特定编程问题已经变得司空见惯了,以至于可以被视为经典。从简单的只需寥寥数行代码就能够解决的问题,到复杂的需要跨多个章节来构建系统的问题,这些问题范围很广。有些问题涉及人工智能,有些问题仅涉及常识,有些问题是实际存在的,而有些问题是虚构的。

本书面向的读者

Java被广泛应用于移动应用程序开发、企业网站开发、计算机科学教育、金融软件等领域。有时,人们批评Java过于冗长且缺乏某些现代特性,但是自从Java诞生以来,它可能比其他任何一种编程语言都更影响人们的生活。Java能够流行必定是有其原因的。Java最初被其创造者James Gosling描绘成更好的C++,这种语言能够提供面向对象编程的能力,同时引入安全特性并简化了C++中一些令人沮丧的问题。在我看来,Java在这方面取得了巨大的成功。

Java是一种非常棒的通用面向对象语言。然而,许多人开始觉得它刻板乏味,无论是Android开发人员还是企业网站开发人员,他们在使用这种语言的大部分时间里感觉就只是在“调用API”。他们把大量时间花在学习SDK或者库的细枝末节上,而不是去解决有趣的问题。本书旨在为这些程序员提供可以缓解这种状况的途径。还有一些程序员,他们从来没有接受过计算机科学相关课程的教育,而这些课程能够教会他们所有能够用来解决问题的强大技术。如果你是只会Java但是不懂计算机科学课程内容的程序员的话,那么这本书非常适合你。

还有一些程序员在从事软件开发工作很长一段时间后,会把Java作为第二、第三、第四甚至第五种语言来学习。对于他们来说,这些已经在其他语言中遇到过的老问题有助于加快对Java的学习速度。本书可以作为他们求职面试前很好的复习材料,为他们揭示一些以前在工作中没有考虑过的问题求解技巧。

本书适合中级和富有经验的程序员阅读。想要加深对Java知识理解的老练程序员,可以发现本书中提到的很多问题似曾相识,在之前上过的计算机科学或者编程课程上都遇到过。中级程序员可以通过他们熟悉的Java语言来学习这些经典的问题。准备进行编程面试的开发人员会发现本书是非常有价值的复习材料。

除了专业程序员,本书对于对Java感兴趣的计算机科学本科生来说也会很有帮助。本书没有对数据结构和算法进行严谨的介绍。这不是一本关于数据结构和算法的教材。你不会在本书中看到证明或者大量使用大O符号的情况。相反,它被定位为关于问题求解技术的入门实践指南,仿佛是数据结构、算法和人工智能课程融合的产物。

再次强调一下,本书需要你具备Java语法和语义的相关知识。没有编程经验的读者无法从本书中受益,而不具备Java经验的程序员也势必会陷入苦战。换句话说,本书是一本面向Java程序员和计算机科学专业学生的书。

本书的结构:路线图

第1章介绍大多数读者可能已经熟知的问题求解技术。像递归、记忆化和位运算这类内容是后续章节讨论其他技术的基础。

第2章重点介绍搜索问题。搜索是一个非常大的主题,本书中的大部分问题都可以归到这个主题下。本章介绍最基本的搜索算法,包括二分搜索、深度优先搜索、广度优先搜索和A*搜索。

第3章介绍如何建立一个框架来解决广泛的问题。这些问题可以用相互之间受到约束的有限领域变量来进行抽象,包括经典的八皇后问题、澳大利亚地图着色问题以及字谜问题。

第4章探索图算法。对于初学者来说,这些算法的适用范围非常广。本章将介绍如何构建图数据结构,然后使用它来解决几个经典的优化问题。

第5章探讨遗传算法,这种算法在不确定性上要比本书中的大多数算法大得多,但有时可以解决那些传统算法无法在合理的时间内解决的问题。

第6章介绍k均值聚类,这可能是本书中算法最具体的一章。这种聚类技术实现简单,易于理解,适用范围广。

第7章解释什么是神经网络,旨在让读者领略简单神经网络究竟是什么样子的。本章不会全面介绍这个令人兴奋而又不断发展的领域,而是介绍如何在不使用外部库的情况下根据基本原理来构建神经网络,让你真正了解神经网络究竟是如何工作的。

第8章介绍双人博弈中的对抗搜索。本章将探索一种被称为极小化极大的搜索算法,该算法可以用来开发国际象棋、国际跳棋和四子棋程序。

第9章涵盖一些书中其他章节没有提及的有趣问题。

第10章是对Oracle的Java语言架构师布赖恩·戈茨(Brian Goetz)的访谈,他指导了该语言的开发工作。他为读者提供了一些有关编程和计算机科学的明智建议。

关于代码

本书源代码是基于Java 11编写的,而且利用了Java 11的某些新特性,因此有些代码可能无法在早期的Java版本下运行。与其耗尽心血尝试在早期Java版本中运行代码,还不如在开始阅读本书之前事先下载好新版本的Java。之所以选择Java 11版本,是因为该版本是撰写本文时Java所发布的最新LTS(Long-Term Support,长期维护)版本。事实上,其中大量代码都可以在Java 8及之后的版本中运行。据我所知,仍有很多程序员出于各种各样的原因(比如Android)在使用Java 8,但是我希望能在使用较新Java版本的同时,通过讲授一些该语言的新特性来为读者提供额外的价值。

本书中的代码只使用了Java标准库,因此可以在所有支持Java的操作系统(例如macOS、Windows、GNU/Linux等)上运行。虽然这些代码在所有可能的Java实现版本中都能运行,但是目前只基于OpenJDK(一种主要的Java实现版本,可以从https://openjdk.java.net上获取)进行了测试。

本书没有介绍如何使用Java工具,例如编辑器、IDE和调试器。书中的源代码可以通过GitHub代码仓库(https://github.com/davecom/ClassicComputerScienceProblemsInJava)获取。源代码按章分类放到了对应的文件夹中。当你阅读每一章时,你可以在每个代码清单的标题中看到对应的源文件名,并可以在代码仓库的对应文件夹中找到该源文件。

请注意,代码仓库是基于Eclipse工作区进行组织的。Eclipse是一个流行的免费Java IDE,可以在三大操作系统上使用,并且可以从https://www.eclipse.org获得。使用源代码仓库最简单的方式就是下载后将其以Eclipse工作区的方式打开,然后展开src目录和以章命名的包,用鼠标右键单击(或者在Mac上按住Ctrl+鼠标左键)包含main()方法的文件,在弹出的菜单里选择Run As>Java Application来运行示例问题的解决方案代码。本书不会提供关于Eclipse的教程,因为我相信Eclipse对于绝大多数中级程序员来说很容易上手。此外,我希望多数程序员能在其他的Java环境下使用本书。

由于只使用了标准Java库,所以你可以选择任意一种你喜欢的IDE(例如NetBeans、IntelliJ等)来运行本书中的源代码。但需要注意的是,如果你选择了其他IDE的话,我无法为项目的导入过程提供支持,尽管这项工作非常简单。绝大多数IDE都可以从Eclipse导入。

简而言之,如果你需要从零开始设置计算机以便运行书中的源代码的话,可以执行以下的操作:

1)从https://openjdk.java.net上下载Java 11或更新的版本并安装。

2)从https://www.eclipse.org上下载Eclipse并安装。

3)从代码仓库https://github.com/davecom/ClassicComputerScienceProblemsInJava上下载本书的源代码。

4)在Eclipse中打开下载好的代码文件夹作为工作区。

5)用鼠标右键单击想运行的源代码文件,并选择Run As→Java Application来运行代码。

本书没有提供图形输出或使用图形用户界面(Graphical User Interface, GUI)的示例。这是为什么呢?因为我们要用尽可能简洁易读的解决方案来解决提出的问题。通常,给出图形会非常麻烦,相较于描述问题中的技术或算法的方式,它们会使解决方案变得异常复杂。

此外,由于没有使用任何GUI框架,所以本书中所有的代码都是可移植的。可以在Linux的命令行界面中使用内嵌的Java发行版本来运行代码,就像在Windows桌面上运行一样简单。同样,就像许多高级Java书籍所采用的方式一样,刻意不采用任何外部库,只用到了Java标准库中的包。这又是为什么呢?因为我们要从基本原理来讲授解决问题的技术,而不是“安装一个解决方案”。通过从头开始解决每一个问题,你将会了解那些流行的库在幕后是如何工作的。起码只使用标准库可以使代码更易于移植和运行。

并不是说有时候基于文字的解决方案比图形解决方案更能阐释算法。这不是本书关注的内容,它只会徒增不必要的复杂性。

其他在线资源

这是Manning出版社出版的“经典计算机科学问题”系列的第三本书。第一本书Classic Computer Science Problems in Swift于2018年出版,第二本书Classic Computer Science Problems in Python于2019年出版。我希望在这个系列的每一本书中通过不同的编程语言来讲授(几乎)相同的计算机科学问题。

如果你喜欢这本书,并且计划学习刚好被本系列所覆盖的另一种语言的话,你会发现直接学习本系列的另一本书是掌握那门语言的便捷方法。目前该系列覆盖Swift、Python和Java语言。由于我在这些语言方面都有丰富的经验,所以这三本书都是由我一个人编写的。我们已经在商讨该系列未来出版的书籍会请其他语言专家一起来编写的计划。如果你喜欢本书,我建议你持续关注本系列的其他书籍。有关该系列的更多信息,请访问https://classicproblems.com/。