演算法之漢諾塔
演算法的概念
- 計算過程,解決問題的方法
- Niklaus Wirth: '程式=資料結構+演算法'
時間複雜度
看下面四組程式碼時間執行最短的是哪個?
print('hello world') O(1) for i in range(n): O(n) print('hello world') for i in range(n): O(n^2) for j in range(n): print('hello world') for i in range(n):O(n^3) for j in range(n): for k in range(n): print('hello world')
用什麼方式來體現演算法執行的快慢?引入事件複雜度的概念
用來評估演算法執行效率的一個式子
print('hello world') print('hello python') print('hello cyn') 上面按理來說運行了三次print應該O(3) for i in range(n): print('hello world') for j in range(n): print('hello world') 這個應該運行了O(n)+O(n^2)次的print while n > 1: print(n) n = n / 2 如果N=64的情況下,應該輸出了6次print, log264=6 應該為O(logN)=6
理論上是這麼說的,但是由於複雜度本身就是一個大概的估值,沒有精確,所以,當N的值無窮大的時候,可以直接忽略掉N^2 + N後面的那個N對於N^2的結果就會越少
一般來說時間複雜度高的演算法比複雜度低的演算法慢
常見的時間複雜度:
o(logn)肯定是小於O(n),因為N為64的情況下,前面僅僅輸出了6次
適用於絕大多數簡單情況的時間複雜度判斷:
- 先確定問題規模N
- 再看看是否有迴圈減半的過程 ----- logn
- k層關於n的迴圈 --- n的k次方
空間複雜度
用來評估演算法記憶體佔用大小的式子
空間複雜度的表示方式與時間複雜度完全相同:
演算法使用了幾個變數: O(1)
演算法使用了長度為N的一維列表: O(n)
演算法使用了M行N列的二維列表: o(mn)
時間遠遠比空間重要,因為對於公司來說,使用者體驗高於一切,記憶體相對來說也比較便宜。這個過程叫空間換時間。
遞迴思想
- 呼叫自身
- 結束條件
當x=3的時候,程式輸出的結果
def func3(x):
if x > 0:
print(x)
func3(x-1)
3
2
1
def func4(x):
if x > 0:
func3(x-1)
print(x)
1
2
3
造成上面兩次出現結果不同的原因是,看下面的圖:
黑色代表輸出,紅色代表函式的呼叫,解釋過程如下,先呼叫函式func3,輸出3,再呼叫func3輸出2,再呼叫fuc3輸出1,結束。
再看第二張圖反之:
黑色代表輸出,紅色代表函式的呼叫,解釋過程如下,先呼叫函式func3,載入了3,再呼叫func3載入了2,再呼叫fuc3載入1,但是程式是從上而下執行的,載入完後輸出的結果為1,2,3。
遞迴例項:漢諾塔問題
大焚天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。
大焚天命令婆羅門把圓盤從下面開始按照大小順序重新擺放在另一根柱子上。
在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。
64根柱子移動完畢之日,就是世界毀滅之時
def hanoi(n, a, b, c):
if n > 0:
hanoi(n-1, a, c, b)
print('moving from %s to %s' % (a, c))
hanoi(n-1, b, a, c)
hanoi(3, 'A', 'B', 'C')
moving from A to C
moving from A to B
moving from C to B
moving from A to C
moving from B to A
moving from B to C
moving from A to C
時間複雜度:
漢諾塔移動次數的遞推式:h(x) = 2(x-1)+1
h(64) = 18446744073709551615
總共需要5800億年