第三節課程,介紹的是迭代法。git
前兩節筆記的文章:程序員
迭代法,簡單來講,其實就是不斷地用舊的變量值,遞推計算新的變量值。github
這裏採用一個故事來介紹什麼是迭代法,這個故事是講述一個國王要重賞一個作出巨大貢獻的臣子,讓臣子提出他想獲得的賞賜,這個聰明的臣子說出了他想獲得的賞賜--在棋盤上放滿麥子,但要求是每一個格子的麥子數量都是前一個格子的兩倍。國王本覺得這個賞賜能夠垂手可得的知足,但真正開始放麥子後,發現即使是拿出全國的糧食也沒法知足的臣子的這個賞賜。算法
這裏咱們能夠用f(n)
表示當前各自的麥子數量,而前一個格子的麥子數量就是f(n-1)
,那麼臣子的要求就能夠這麼表示:編程
f(n) = f(n-1) * 2
f(1) = 1
複製代碼
這也就是迭代法了,而若是用編程來實現,其實就是實現一個循環運算的過程。bash
用 Python 實現這個計算麥子的代碼以下所示:微信
def get_number_of_wheat(grid):
''' \計算放到給定格子數量須要的麥子數量 :param grid: 格子數 :return: '''
# f(1) = 1
wheat_numbers = 1
sums = wheat_numbers
for i in range(2, grid+1):
wheat_numbers *= 2
sums += wheat_numbers
print('when grid = %d, wheats numbers = %d' % (grid, sums))
return sums
複製代碼
簡單的測試例子:less
if __name__ == '__main__':
print('compute numbers of wheat!')
numbers_grid = 63
get_number_of_wheat(numbers_grid)
print('finish')
複製代碼
給定格子數量是 63 個,輸出結果以下:機器學習
compute numbers of wheat!
when grid = 63, wheats numbers = 9223372036854775807
finish
複製代碼
因此這個天文數字是 19 位數--9223372036854775807,真的是很是的多!假設一袋 50 斤的麥子估計有 130 萬粒麥子,那麼這個計算結果是至關於 70949 億袋 50 斤的麥子!編程語言
看完上述例子,相信應該對迭代法的基本概念比較瞭解了,而迭代法的基本步驟也很簡單,分爲三個步驟:
f(n)
和f(n-1)
f(n)=f(n-1)*2
f(1)=1
,而終止條件就是達到給定的格子數了。那麼迭代法有什麼應用呢?
其實,它在數學和計算機領域都有很普遍的應用,如:
接下來會重點介紹求數值的解和查找匹配記錄,這兩個應用其實都是採用二分法來實現。
迭代法除了用於計算龐大的數字,還能夠幫助咱們進行無窮次地逼近,求得方程的精確或者近似解。
舉個例子,咱們要計算一個給定的正整數n(n>1)
的平方根,而且不能採用編程語言自帶的函數,應該如何計算呢?
首先咱們能夠明確的是,對於給定的正整數n
,它的平方根確定是小於它,但大於1,也就是這個平方根的取值範圍是 1 到 n
,在這個範圍內求一個數值的平方等於n
。
這裏就能夠經過採用剛剛說的二分法。每次查看區間內的中間值,檢查它是否符合標準。
好比咱們要求 10 的平方根,尋找的區間就是[1,10]
,第一個中間值就是(1+10)/2=11/2=5.5
,而 5.5 的平方等於 30.25,明顯比 10 大,因此尋找區間變成 5.5 的左側,也就是[1, 5.5]
,中間值就是 3.25,但 3.25 的平方是 10.5625,依然大於 10,尋找區間變爲[1, 3.25]
,中間值變爲 2.125, 2.125 的平方是 4.515625,小於 10,因此區間就是[2.125, 3.25]
,這樣繼續尋找和計算中間值的平方,直到發現某個數的平方正好是 10。
具體步驟以下圖:
這裏用代碼實現,以下圖所示:
def get_square_root(n, threshold, max_try):
''' 計算大於 1 的正整數的平方根 :param n: 給定正整數 :param threshold: 偏差的閾值 :param max_try: 最大嘗試次數 :return: '''
if n <= 1:
return -1.0
# interval boundary 區間的左右邊界
left = 1.0
right = float(n)
for idx in range(max_try):
# 防止溢出
middle = left + (right - left) / 2
square = middle * middle
# 偏差
delta = abs(square / n - 1)
if delta <= threshold:
return middle
else:
if square > n:
right = middle
else:
left = middle
return -2.0
複製代碼
簡單的測試例子:
square_root = get_square_root(10, 0.000001, 10000)
if square_root == -1.0:
print('please input a number > 1')
elif square_root == -2.0:
print('cannot find the square root')
else:
print('square root==', square_root)
複製代碼
輸出結果是:
square root== 3.1622767448425293
複製代碼
這裏代碼中,設置了兩個控制迭代結束的參數:
threshold
:偏差的閾值,用於控制解的精度。理論上二分法能夠經過無限次迭代求到精確解,但實際應用還須要考慮時間和計算資源,因此通常咱們只須要一個近似解,而不須要徹底精確的數據;max_try
:控制迭代的次數。設置這個參數也是爲了不使用while True
循環可能致使的死循環,固然理論上設置了threshold
是能夠避免死循環的,但這是一個良好的編程習慣,主動避免產生的可能性。二分法經過迭代式逼近,不只能夠求得方程的近似解,還能夠幫助查找匹配的記錄。
這裏老師給的例子是在天然語言處理中,處理同義詞或者近義詞的擴展問題。這時,你是會有一個詞典,用於記錄每一個單詞的同義詞或者近義詞。對於一個待查找單詞,咱們須要在字典找到這個單詞,以及對應的全部同義詞和近義詞,而後進行拓展,例如對於單詞--西紅柿
,它的同義詞包括了番茄
和tomato
。
詞典以下表格所示:
詞條 | 同義詞1 | 同義詞2 | 同義詞3 |
---|---|---|---|
西紅柿 | 番茄 | tomato | ... |
... | ... | ... | ... |
當處理文章的時候,遇到「西紅柿」這個單詞,就在字典裏查找,返回「番茄」和「tomato"等同義詞或者近義詞,並添加到文章做爲同義詞/近義詞的拓展。
這裏要解決的問題就是如何在字典查詢匹配單詞的問題。一種作法就是哈希表。而若是不用哈希表的方法,還能夠採用二分查找法。二分查找法進行字典查詢的思路以下:
相比於利用二分法查找方程解,二分查找必需要求數據是有序的!
用代碼實現以下:
def search_word(dictionary, word):
''' 查找匹配單詞 :param dictionary: 排序後的字典 :param word:待查找單詞 :return: '''
if dictionary is None:
return False
if len(dictionary) < 1:
return False
left = 0
right = len(dictionary) - 1
while left <= right:
middle = int(left + (right - left) / 2)
if dictionary[middle] == word:
return True
else:
if dictionary[middle] > word:
right = middle - 1
else:
left = middle + 1
return False
複製代碼
簡單的測試代碼:
print('find word in dictionary')
dict_list = ['i', 'am', 'coder']
dict_list = sorted(dict_list)
print('sorted dict:', dict_list)
word_to_find = 'am'
found = search_word(dict_list, word_to_find)
if found:
print('word "%s" found in dictionary--%s!' % (word_to_find, dict_list))
else:
print('cannot find the word "%s"' % word_to_find)
複製代碼
輸出結果:
find word in dictionary
sorted dict: ['am', 'coder', 'i']
word "am" found in dictionary--['am', 'coder', 'i']!
finish
複製代碼
迭代法的介紹就到這裏了!上述源代碼地址:
歡迎關注個人微信公衆號--機器學習與計算機視覺,或者掃描下方的二維碼,你們一塊兒交流,學習和進步!