第一章、 算法簡介
一些常見的大O運行時間
》 O(log n)
,也叫對數時間,這樣的算法包括二分查找。
》 O(n)
,也叫線性時間,這樣的算法包括簡單查找。
》 O(n * log n)
,這樣的算法包括第4章將介紹的快速排序——一種速度較快的排序算法。
》 O(n2)
,這樣的算法包括第2章將介紹的選擇排序——一種速度較慢的排序算法。
》 O(n!)
,這樣的算法包括接下來將介紹的旅行商問題的解決方案——一種非常慢的算法。
小結
》 二分查找的速度比簡單查找快得多。
》 O(log n)
比O(n)
快。需要搜索的元素越多,前者比后者就快得越多。
》 算法運行時間并不以秒為單位。
》 算法運行時間是從其增速的角度度量的。
》 算法運行時間用大O表示法表示。
第二章、選擇排序
總結
? 計算機內存猶如一大堆抽屜。
? 需要存儲多個元素時,可使用數組或鏈表。
? 數組的元素都在一起。
? 鏈表的元素是分開的,其中每個元素都存儲了下一個元素的地址。
? 數組的讀取速度很快。
? 鏈表的插入和刪除速度很快。
? 在同一個數組中,所有元素的類型都必須相同(都為int、double等)。
第三章、 遞歸、棧
關于遞歸
我懷著激動的心情編寫本章,因為它介紹的是遞歸——一種優雅的問題解決方法。遞歸是我 最喜歡的主題之一,它將人分成三個截然不同的陣營:恨它的、愛它的以及恨了幾年后又愛上它 的。我本人屬于第三個陣營 --- 作者
計算機在內部使用被稱為調用棧的棧。我們來看看計算機是如何使用調用棧的。下面是一個 簡單的函數。
def greet(name):
print( "hello, " + name + "!" greet2(name) )
print( "getting ready to say bye..." bye() )
這個函數問候用戶,再調用另外兩個函數。這兩個函數的代碼如下。
def greet2(name):
print( "how are you, " + name + "?")
def bye():
print ("ok bye!")
現在你又回到了函數
greet
。由于沒有別的事情要做,你就從函數greet
返回。這個棧用于存儲多個函數的變量,被稱為調用棧。
遞歸調用棧
遞歸函數也使用調用棧!來看看遞歸函數factorial的調用棧。factorial(5)
寫作5!,其
定義如下:5! = 5 * 4 * 3 * 2 * 1
。同理,factorial(3)
為3 * 2 * 1。下面是計算階乘的遞歸函數。
def fact(x):
if x == 1:
return 1
else:
return x * fact(x-1)
下面來詳細分析調用fact(3)
時調用棧是如何變化的。別忘了,棧頂的方框指出了當前執行 到了什么地方。
使用棧雖然很方便,但是也要付出代價:存儲詳盡的信息可能占用大量的內存。每個函數調 用都要占用一定的內存,如果棧很高,就意味著計算機存儲了大量函數調用的信息。在這種情況 下,你有兩種選擇。
? 重新編寫代碼,轉而使用循環。
? 使用尾遞歸。這是一個高級遞歸主題,不在本書的討論范圍內。另外,并非所有的語言
都支持尾遞歸。
小結
? 遞歸指的是調用自己的函數。
? 每個遞歸函數都有兩個條件:基線條件和遞歸條件(遞歸用巧勁)
? 棧有兩種操作:壓入和彈出。
? 所有函數調用都進入調用棧。
? 調用棧可能很長,這將占用大量的內存。
遞歸條件指的是函數調用自己,而基線條件則 指的是函數不再調用自己,從而避免形成無限循環。