本書介紹了算法設計與分析的基本技巧,主要包括遞歸、分治、動態(tài)規(guī)劃、貪心和隨機等算法,以及利用這些算法求解計算問題的時間復雜度分析等內(nèi)容。通過諸多有趣的實例,向讀者介紹了算法設計的思想,以便讀者能形成算法思維的固定模式去解決問題。在介紹每一類算法范式以及分析算法復雜度時,都力求建立直觀的思維過程,而摒棄過深的數(shù)學證明。書中所有算法均采用 Python語言描述,讀者能從中學習到許多算法實現(xiàn)的技巧,從而提高編寫程序的能力。
本書可作為高等學校計算機專業(yè)大一、大二或者學習過程序設計的非計算機專業(yè)學生的算法設計與分析教材。
如果將要處理的數(shù)據(jù)、問題看作是食材,那么算法就是將食材轉(zhuǎn)化成各種令人垂誕美食的過程。中國菜肴到處都是充滿想象力的轉(zhuǎn)化,將原本普通的食材(大豆和糯米等)轉(zhuǎn)化為營養(yǎng)和風味都令人嘆為觀止的食物(豆腐、酒釀和醬料等等)。《算法設計與分析(Python)》的主線就是轉(zhuǎn)化,它不僅有問題的轉(zhuǎn)化,也有方法的轉(zhuǎn)化。通過問題的轉(zhuǎn)化將問題化繁為簡,通過方法的轉(zhuǎn)化以便融會貫通各種算法設計的技巧。 算法設計與分析是計算機專業(yè)非常重要的一門基礎課程,它不僅是諸多計算機專業(yè)課程的基礎,也是諸多信息科技類公司在招聘員工時,筆試與面試重點考核的內(nèi)容。算法設計與分析已經(jīng)有了諸多經(jīng)典的著作,然而筆者在教學過程發(fā)現(xiàn),已有的算法設計與分析教材往往并不適合初學算法課程的同學。主要是這些著作往往需要較多的程序設計與數(shù)據(jù)結(jié)構的背景知識!端惴ㄔO計與分析(Python)》的內(nèi)容編排并未要求過多的程序設計或者數(shù)學基礎,只需要有一定程序設計基礎即可,具體而言就是能正確寫出一個從1加到100 的函數(shù)即可。尤其是,已有的算法著作在分析算法復雜度時,為了結(jié)果的嚴謹往往忽視了數(shù)學分析后的直觀解釋。 《算法設計與分析(Python)》擯棄了算法分析過程中繁瑣的數(shù)學證明,而主要通過圖示等手段給出算法分析結(jié)果的直觀解釋。此外,已有的教材描述算法的語言要么是偽代碼,要么是C,C 或者Java這類高級程序語言。采用偽代碼描述算法可以獲得更為精簡的描述,然而缺少可執(zhí)行的結(jié)果會降低初學者對算法結(jié)果的直觀印象。而使用C,C 或者Java這類高級程序語言描述算法,會降低算法描述的簡潔性,還會增加初學者調(diào)試出正確結(jié)果的難度。為此,《算法設計與分析(Python)》的算法采用Python 描述。Python 是復雜度介于偽代碼和C,C 之間的一類語言,其語法簡單直觀,如果有一定程序設計基礎的學生可以在1 小時內(nèi)入門!端惴ㄔO計與分析(Python)》可作為計算機專業(yè)大一、大二或者學習過程序設計的非計算機專業(yè)學生的算法設計與分析教材。
前言
算法設計與分析是計算機專業(yè)非常重要的一門基礎課程,它不僅是諸多
計算機專業(yè)課程的基礎,也是許多信息科技類公司招聘程序員時,筆試與面
試重點考核的內(nèi)容。算法設計與分析已經(jīng)有了諸多經(jīng)典的著作,比如美國麻
省理工學院( MIT)幾位教授合著的《算法導論》
①等。然而,這些經(jīng)典著
作當作教材使用時,都會存在對內(nèi)容進行適當裁剪,以便更適合 48或者 32
個學時教學的問題。我們寫本書的目的就是對初等算法內(nèi)容進行合理的編排
,讓初學者能很快地掌握解決計算問題的常用算法,以及分析算法效率的方
法。
本書算法均采用 Python語言進行描述, Python是一類解釋性語言,其語法
簡單直觀,有一定程序設計基礎的學生可以很快入門。 Python語法簡單并不
意味著功能弱,它在科學計算、 Web應用等諸多領域都有著廣泛的應用。國
外知名的高校,如麻省理工學院,也在算法設計課中采用 Python語言描述。
與采用偽代碼描述算法的書比較而言,采用 Python描述算法能給讀者直接的
運算結(jié)果,從而可以使讀者更易于揣摩算法實現(xiàn)的技巧。
計算機算法不僅涉及諸多理論,還有各種技術細節(jié)。比如介紹隨機算法時,
有些執(zhí)行時間的分析就需要較多的概率論知識;而算法實現(xiàn)技術細節(jié)則不僅
關注如何存儲數(shù)據(jù),甚至對執(zhí)行算法的硬件環(huán)境也會考慮在內(nèi)。本書的內(nèi)容
安排則介于兩者之間,在數(shù)學分析與實現(xiàn)之間期望取得合理的平衡。首先,
在分析算法效率時盡量避免過深的數(shù)學證明,但關鍵步驟依然會給出直觀的
解釋。其次,在實現(xiàn)算法時本書盡量利用 Python已有的數(shù)據(jù)結(jié)構和庫函數(shù),
從而簡化算法實現(xiàn)的技術難度。
如果將要處理的數(shù)據(jù)、問題看作是食材,那么算法就是將食材轉(zhuǎn)化成各
種令人垂涎的美食的過程。中國菜肴到處都是充滿想象力的轉(zhuǎn)化,將原本普
通的食材(如大豆和糯米等)轉(zhuǎn)化為營養(yǎng)和美味的食物(豆腐、酒釀和醬料
等)。本書的主線就是轉(zhuǎn)化,它不僅有問題的轉(zhuǎn)化,也有方法的轉(zhuǎn)化(如圖
1所示)。通過問題的轉(zhuǎn)化將問題化繁為簡,通過方法的轉(zhuǎn)化以便融會貫
通各種算法設計的技巧。
本書主要內(nèi)容
由于計算機已經(jīng)成為現(xiàn)代科技、生活不可缺少的工具。因此,解決計算問題
的算法涉及的內(nèi)容可以說包羅萬象,從簡單的排序和查找到復雜的語音識別
、文字翻譯,甚至
①見參考文獻 [1]。
圖 1本書的主線 轉(zhuǎn)化
游戲等都離不開算法。本書內(nèi)容涵蓋了大部分的經(jīng)典算法,主要內(nèi)容包括遞
歸算法、分治算法、排序算法、動態(tài)規(guī)劃算法、圖搜索算法、最大流算法、
隨機算法和算法復雜度。
第 1章主要介紹算法的基本概念,通過實例向讀者展示解決同一問題的不同
算法的確存在效率上顯著的差異。第 2章介紹度量算法效率的記號,以及分
析簡單函數(shù)執(zhí)行時間的常用技巧。第 3章通過解決文檔比較、單詞拼寫糾正
和穩(wěn)定匹配這三個有趣的問題,幫助讀者熟悉 Python語言。第 4章介紹了遞
歸算法以及遞歸函數(shù)求解,從而為后續(xù)章節(jié)復雜的算法設計與分析打下一定
的基礎。第 5章介紹了組織數(shù)據(jù)的兩個常用方法:排序和數(shù)據(jù)結(jié)構,主要強
調(diào)遞歸在組織數(shù)據(jù)中的應用,幫助讀者進一步熟悉采用遞歸求解問題的過程
。
第 6章到第 11章則分別介紹了分治算法、圖搜索、貪心、動態(tài)規(guī)劃、最大流
和隨機算法。通過各種有趣的問題,向讀者展示轉(zhuǎn)化的基本技巧,以便更好
地幫助讀者建立采用算法思維去解決問題的習慣。第 12章介紹了算法復雜度
,幫助讀者明確哪類問題可解,而哪類問題目前不可解。
本書由程振波總體設計和規(guī)劃。第 2到第 12章由程振波編寫,第 1章由程振
波、李曲和王春平編寫。全書由程振波統(tǒng)稿。
如何使用本書
本書的內(nèi)容框架是筆者在浙江工業(yè)大學算法設計與分析課程的講義,內(nèi)
容的編排則參考了 MIT的算法課程 6 006。①因此,本書從內(nèi)容安排來說非
常適合學時為 48或者 32學時的算法課程。對于教師而言,可以直接按照本
書的章節(jié)安排教學計劃。為了便于教師安排教學,具體的教學建議如下:
① MIT將算法設計與分析課程分解成了兩門課。一門是 6 006,該課程
主要是算法的入門課程,可以面向各個專業(yè)開設。另一門則是 6 046,這是
一門面向有一定算法基礎的學生開設的算法課程。
前言 III
教學內(nèi)容學習要點及教學內(nèi)容課時安排
第 1章引言 掌握算法的定義。了解算法的來源,理解現(xiàn)實生活中解決問題
的辦法與算法之間的關系;掌握衡量算法的屬性,尤其是正確性和時間效率
對算法的意義。 2
掌握算法效率的基本概念。理解直接計算某個輸入規(guī)模的時間來衡量算法效
率的不足;了解漸進分析法以及多項式時間復雜度與指數(shù)時間復雜度的區(qū)別
。
了解求解問題可能存在效率不同的算法。掌握求解一維高點問題的簡單算法
及改進算法。
掌握哈希表的基本概念。
第 2章漸進分析與 Python計算模型 掌握運行算法的簡化模型。了解單處理
器隨機訪問機器模型的結(jié)構,以及運行在該機器模型上常見指令的執(zhí)行時間
。 2
掌握算法漸進分析的概念。熟悉三種漸進函數(shù)的定義,以及常見函數(shù)的漸進
表示。
熟練掌握基本函數(shù)的漸進分析。熟悉 Python的判斷、循環(huán)語句寫法,熟練
掌握 Python的基本數(shù)據(jù)結(jié)構的使用。掌握較為復雜的函數(shù)的時間復雜度分析
,如求最大值、二分搜索等。
第 3章問題求解與代碼優(yōu)化 基本掌握使用 Python求解較為復雜的問題。
了解文檔比較問題及其算法。 2
了解單詞拼寫問題及其實現(xiàn)算法。
了解穩(wěn)定匹配問題及其實現(xiàn)算法。
第 4章遞歸算法與遞歸函數(shù) 熟悉遞歸的組成結(jié)構。熟練掌握遞歸算法的兩
個基本組成,以及它們各自的作用。 4或 6
掌握遞歸算法執(zhí)行的過程。了解遞歸算法在機器模型中的運行過程。
熟練掌握常見問題的遞歸求解方法。熟悉回文、全排列和漢諾塔問題的遞歸
算法。
熟練掌握求解標準遞歸函數(shù)
T (n) = aT (n/b) f(n)的方法。掌握替換法
和主分析法求解遞歸函數(shù)的過程,理解主分析法的三類條件及其對應的解。
續(xù)表
教學內(nèi)容
學習要點及教學內(nèi)容
課時安排
第 5章
排序與樹結(jié)構 熟悉插入排序、選擇排序和合并排序算法。能熟練
4 寫出這三個排序算法的實現(xiàn)代碼以及它們各自的
時間復雜度。 掌握二叉搜索樹的基本數(shù)據(jù)操作。能從使用場景的
角度理解二叉樹與數(shù)組、鏈表等數(shù)據(jù)結(jié)構的不同。
掌握基于二叉搜索樹常見的數(shù)據(jù)操作,比如插入、
刪除和查找等。
熟練掌握堆結(jié)構的應用場景和數(shù)據(jù)操作。熟悉建堆
算法及其時間復雜度分析,了解基于堆的排序和合
并 k個有序序列等應用。
第 6章
分治算法 掌握分治算法求解問題的三個基本步驟。 6
掌握利用分治法求解一些典型問題,如序列最大差
值區(qū)間、統(tǒng)計逆序數(shù)、空間點最小距離和序列中第
k小的數(shù)等問題。
熟悉如何將問題進行分解,以及合并子問題解的常
用技巧。掌握分治算法的時間復雜度分析。
第 7章
圖搜索算法 熟悉圖的兩種常見表示方法,熟練掌握如何在計算 4
機中存儲圖。了解圖在計算機應用領域常見的應用
場景。
熟練掌握圖上寬度優(yōu)先搜索算法及其算法復雜度
分析,了解利用寬度優(yōu)先搜索解決計算問題的建模
過程。
熟練掌握圖上深度優(yōu)先搜索算法及其算法復雜度
分析,了解利用深度優(yōu)先搜索解決計算問題的建模
過程。
第 8章
貪心算法 了解貪心算法求解優(yōu)化問題的過程。 4
熟練掌握利用貪心算法求解典型的計算問題,如硬
幣找零、間隔任務規(guī)劃等問題。了解利用替換法證
明貪心策略是否能獲得全局最優(yōu)解的過程。
熟練掌握貪心算法在兩個典型圖搜索中的應用,即
單源最短路徑和最小生成樹。理解單源最短路徑和
最小生成樹算法中,利用合理的數(shù)據(jù)結(jié)構優(yōu)化算法
復雜度的技巧。
教學內(nèi)容
學習要點及教學內(nèi)容
課時安排
第 9章動態(tài)規(guī)劃算法 理解動態(tài)規(guī)劃求解優(yōu)化問題的典型步驟,以及動態(tài)規(guī)
劃算法求解計算問題的時間復雜度分析。 6
熟練掌握利用動態(tài)規(guī)劃算法求解一維、二維等典型優(yōu)化問題,如斐波那契數(shù)
、拾撿硬幣、連續(xù)子序列的最大值、矩陣的括號、 0-1背包問題等。
對于簡單問題能畫出其動態(tài)規(guī)劃表,并能從中得到問題的解。
第 10章最大流算法 掌握最大流問題的定義,了解流量、容量以及它們之
間的關系。 2
掌握通過增廣路徑求最大流問題的 Ford-Fulkerson和 Edmond-Karp算法,
理解這兩個算法之間的異同。
了解將計算問題轉(zhuǎn)化為最大流問題的基本過程。掌握通過最大流算法求解二
向圖最大匹配和文件傳輸中的不重合邊等問題的方法。
第 11章隨機算法 了解兩種典型的隨機算法:蒙特卡洛和拉斯維加斯算法
,以及它們之間的異同。 2
熟練掌握利用隨機算法求解典型的計算問題,如矩陣乘積結(jié)果驗證、快速排
序、選擇第 k小的數(shù)和最小割驗證等。
了解隨機快速排序算法復雜度分析過程。
第 12章算法復雜度 了解如何根據(jù)問題求解的難易程度對計算問題進行基
本分類。 2
理解 P問題、 NP問題和 NPC問題的定義。
了解幾個典型的 NPC問題,理解為什么證明 P是否等于 NP是計算機領域最
為重要的問題之一。
對學生而言,先閱讀書中各章節(jié)內(nèi)容,然后運行書中代碼以便檢驗對算法的
理解程度。特別是,學生還應該獨立重復出書中各個問題的算法,這個過程
就好比學習圍棋的選手進行復盤一樣。如果僅僅是了解算法原理,而沒有通
過寫代碼來實現(xiàn)算法,將不利于讀者培養(yǎng)獨立解決問題的能力。
此外,除了課后習題外,我們還建議學生在 leetcode ①上刷題。 leetcode
上的題目
① https://leetcode com/
不是國際計算機學會( ACM)的競賽題目,而是各大 IT企業(yè)的面試題目。通
過解題不僅能提高學生算法設計的能力,也對編程能力有極大提高。
閱讀本書需要學生能按照教程( http://www python org/)配置 Python環(huán)
境,知道如何寫一個簡單的包括循環(huán)的函數(shù)。因此,該課程安排在學生上過
一門程序語言課程之后較為合適。
致謝
在本書編寫過程中,許多浙江工業(yè)大學的同學閱讀了初稿,尤其感謝李軼、
陳明明、嚴凡等同學給出的許多建議。我們的許多同事也對本書提出了諸多
寶貴建議,他們是呂慧強、錢能和黃德才老師。本書還受到浙江工業(yè)大學校
級重點教材資助,特此感謝。對在本書出版過程中付出辛勤勞動的清華大學
出版社的編輯致以特別的謝意。最后,作者程振波要對他的妻子王玉秀、女
兒程靜萱致以特別的謝意,感謝她們給予的愛和支持,讓他能心無旁騖地完
成書稿。
程振波李曲王春平
2017年 6月