1、前言算法
爲了解決本身對傳說中高大上的算法的好奇之心,特地找了一本算法入門的書籍(算是科普讀物)《算法圖解》進行研究。數組
本篇文章是對這本書的一些筆記和精簡。·持續更新app
2、目錄ide
3、算法簡介函數
簡單查找性能
本質:列表中逐個比較spa
簡單實現:code
def search(target_list,item): for i in target_list: if i == item: return i return None
二分查找blog
本質:每次取中值與item比較,中值比item大了在左邊列表中繼續下一輪,相反中值比item小了,在右邊列表中繼續下一輪取中值。排序
簡單實現:
def binary_search(tlist,item): low = 0 high = len(tlist)-1 while low <= high: mid = int((low + high)/2) if item < tlist[mid]: high = mid-1 elif item >tlist[mid]: low = mid+1 else: return (mid,tlist[mid]) return None
大O表示法
本質:經過執行語句數的數量級來描述程序運行時間,通常以最糟糕的狀況下執行的語句數爲準,例如簡單實現爲O(n),即假定要找的元素在最後一個。忽略數量級前的常數量,如O(5n!)是不必的,直接寫O(n!).
常見時間:
O(1): 常量時間,哈希
O(log2(n)): 對數時間,二分,
O(n): 線性時間,簡單
O(nlog2(n)): 快速排序
O(n2): 選擇排序(冒泡)
O(n!): 旅行商問題
4、選擇排序
數組和鏈表
數組: 內存中連續存儲,隨意查詢元素, 隨機查詢快(知道元素index),增刪改慢(由於有順序,有預設內存空間,中間插入或者超出預留內存,就會從新構建)
鏈表: 內存中分散,每個元素記錄下一個元素位置,隨機查詢慢(只能從第一個日後推),要所有查詢的狀況下也不慢,增刪改快(分散存儲只要更改上一個元素的記錄),
選擇排序(冒泡排序)
本質:每一次選出最大的或最小的元素,循環排序,O(n2)
簡單實現從小到大排序:
def mysort(target_list): new_list = [] while target_list: mini = target_list[0] for i in target_list: if i <= mini: mini = i new_list.append(mini) target_list.remove(mini) return new_list
5、遞歸
遞歸與循環
遞歸優點在於代碼更容易理解
循環優點在於性能更高
基線條件和遞歸條件
基線條件指退出的條件,防止無限遞歸
遞歸條件指函數的自我調用
def condition(i): print(i) if i<0: #基線條件,達到就退出遞歸 return else: condition(i-1) #遞歸條件,實現遞歸
棧
本質:後進先出的結構,(同搭積木,先放的在底下,後方在上面,拿永遠拿最上面的,也是最後放上去的),有壓入彈出兩種操做
簡單例子二:
def test(n): '''階乘函數''' if n== 1: return 1 else: return n*test(n-1)
注意:遞歸是有代價的,一次遞歸就可能建立多個調用棧,當遞歸未結束,調用棧會愈來愈高,佔用內存會愈來愈大,直到程序崩潰,Python默認棧高爲1000,能夠更改。可是更改沒有太大意義,更好的辦法是修改你的算法。
6、快速排序
分而治之(divide and conquer D&C)
本質:遞歸分解問題
簡單例子:
def mysum(target_list): '''求和函數'''if target_list:return target_list[0]+test(target_list[1:]) else: return 0 def mylen(target_list): '''求長度函數''' if target_list: return 1+test(target_list[1:]) else: return 0 def mymax(target_list): '''求最大值函數''' if len(target_list)==2: return target_list[0] if target_list[0]>=target_list[1] else target_list[1] sub_max = test(target_list[1:]) return target_list[0] if target_list[0]>=sub_max else sub_max
快速排序
本質: