一、什麼是算法?算法
算法(Algorithm):一個計算過程,解決問題的方法數據結構
二、複習:遞歸app
遞歸的兩個特色:(1) 調用自身 (2)結束條件dom
def func1(x): print(x) func1(x-1) def func2(x): if x>0: print(x) func2(x+1) def func3(x): if x>0: print(x) func3(x-1) def func4(x): if x>0: func4(x-1) print(x)
func1和func2不是遞歸ide
func3和func4是遞歸,可是結果不同,func3(5)打印的是5,4,3,2,1 而func4(5)結果是1,2,3,4,5函數
三、時間複雜度優化
時間複雜度:用來評估算法運行效率的一個東西ui
小結:spa
時間複雜度是用來估計算法運行時間的一個式子(單位)。3d
通常來講,時間複雜度高的算法比複雜度低的算法快。
常見的時間複雜度(按效率排序)
O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(nlogn)<O(n^3)
不常見的時間複雜度(看看就好)
O(n!) O(2n) O(nn) …
如何一眼判斷時間複雜度?
循環減半的過程O(logn)
幾回循環就是n的幾回方的複雜度
四、空間複雜度
空間複雜度:用來評估算法內存佔用大小的一個式子
五、列表查找
列表查找:從列表中查找指定元素
輸入:列表、待查找元素
輸出:元素下標或未查找到元素
六、順序查找
從列表第一個元素開始,順序進行搜索,直到找到爲止。
七、二分查找
從有序列表的候選區data[0:n]開始,經過對待查找的值與候選區中間值的比較,可使候選區減小一半。
def bin_search(data_set,val): ''' mid:下標 low:每次循環的列表最左邊下標 high:每次循環的列表最右邊下標 :param data_set:列表 :param val: 要找的值 :return: ''' low = 0 high = len(data_set)-1 while low <= high: mid = (low+high)//2 if data_set[mid] == val: return mid elif data_set[mid] > val: high = mid - 1 else: low = mid + 1 return
八、列表排序
將無序列表變爲有序列表
應用場景: 各類榜單 各類表格 給二分查找用 給其餘算法用
輸入:無序列表
輸出:有序列表
九、排序中比較慢的三種: 冒泡排序 選擇排序 插入排序
快速排序
排序NB二人組: 堆排序 歸併排序
沒什麼人用的排序: 基數排序 希爾排序 桶排序
算法關鍵點: 有序區 無序區
十、冒泡排序
首先,列表每兩個相鄰的數,若是前邊的比後邊的大,那麼交換這兩個數
n = len(list),循環了i趟(i=n-1),第i趟循環比較了(j = n-i-1 )次,j是每趟循環比較的次數
import random,time #裝飾器 def cal_time(func): def wrapper(*args,**kwargs): t1 = time.time() ret = func(*args,**kwargs) t2 = time.time() print('time cost: %s \r\nfunc from %s'%(t2-t1,func.__name__)) return func return wrapper @cal_time def bubble_sort(li): for i in range(len(li) - 1): for j in range(len(li) - i - 1): #升續 if li[j] > li[j+1]: li[j],li[j+1]=li[j+1],li[j] #降續 # if li[j] < li[j+1]: # li[j],li[j+1]=li[j+1],li[j] data = list(range(1000)) random.shuffle(data) print(data) bubble_sort(data) print(data)
優化後的冒泡排序:
若是冒泡排序中執行一趟而沒有交換,則列表已是有序狀態,能夠直接結束算法。
import random,time #裝飾器 def cal_time(func): def wrapper(*args,**kwargs): t1 = time.time() ret = func(*args,**kwargs) t2 = time.time() print('time cost: %s \r\nfunc from %s'%(t2-t1,func.__name__)) return func return wrapper @cal_time def bubble_sort(li): for i in range(len(li) - 1): exchange = False for j in range(len(li) - i - 1): #升續 if li[j] > li[j+1]: li[j],li[j+1]=li[j+1],li[j] exchange = True #降續 # if li[j] < li[j+1]: # li[j],li[j+1]=li[j+1],li[j] # exchange = True #這裏是指上一趟,值之間沒有發生交換,就退出循環 if not exchange: break data = list(range(1000)) random.shuffle(data) print(data) bubble_sort(data) print(data)
十一、選擇排序
一趟遍歷記錄最小的數,放到第一個位置; 再一趟遍歷記錄剩餘列表中最小的數,繼續放置;
import random,time #裝飾器 def cal_time(func): def wrapper(*args,**kwargs): t1 = time.time() ret = func(*args,**kwargs) t2 = time.time() print('time cost: %s --> \nfunc from %s'%(t2-t1,func.__name__)) return func return wrapper @cal_time def select_sort(li): for i in range(len(li)-1): min_loc = i for j in range(i+1,len(li)): if li[j] < li[min_loc]: min_loc = j li[i],li[min_loc] = li[min_loc],li[i]
十二、插入排序
def insert_sort(li): for i in range(1,len(li)): tmp = li[i] j = i - 1 while j >= 0 and tmp < li[j]: li[j + 1] = li[j] j -= 1 li[j + 1] = tmp
1三、練習 用冒泡法把打亂的帶ID的信息表排序
import random def random_list(n): ids = range(1000,1000+n) result = [] a1 = ["王","陳","李","趙","錢","孫","武"] a2 = ["丹","澤","","","晶","傑","金"] a3 = ["強","華","國","富","宇","齊","星"] for i in range(n): age = random.randint(16,38) id = ids[i] name = '%s%s%s'%(random.choice(a1),random.choice(a2),random.choice(a3)) dic = {} dic['id'] = id dic['姓名'] = name dic['年齡'] = age result.append(dic) return result def bubble_sort(li): for i in range(len(li)-1): for j in range(len(li)-i-1): if li[j]['id'] > li[j+1]['id']: li[j],li[j+1] = li[j+1],li[j] data1 = random_list(100) random.shuffle(data1) print(data1) bubble_sort(data1) print(data1)
1四、快速排序:快
好寫的排序算法裏最快的
快的排序算法裏最好寫的
快排思路:
取一個元素p(第一個元素),使元素p歸位;
列表被p分紅兩部分,左邊都比p小,右邊都比p大;
遞歸完成排序。
#快排的複雜度是O(nlog(n)),這是一個特殊狀況
#口訣 右手左手一個慢動做,右手左手慢動做重播(遞歸)
import time,random,copy def cal_time(func): def wrapper(*args,**kwargs): t1 = time.time() ret = func(*args,**kwargs) t2 = time.time() print('time cost: %s from %s'%(t2-t1,func.__name__)) return func return wrapper def quick_sort_x(data,left,right): #這裏的left和right是定義列表data,最少有兩個元素 if left<right: #partition分割函數,mid是放好的元素的下標 mid = partition(data,left,right) #如下相似二分 quick_sort_x(data,left,mid-1) quick_sort_x(data,mid+1,right) #快排的複雜度是O(nlog(n)),這是一個特殊狀況 def partition(data,left,right): #獲取左邊的第一個元素,這裏寫left不能寫零,由於後面須要遞歸 tmp = data[left] #終止條件爲當left和right碰上時,因此左小於右時爲while循環的條件(left和right是下標) while left < right: #循環條件是右邊比tmp大,直到找到右邊比tmp小的數,中止循環 while left < right and data[right] >= tmp: right -= 1 #把找到的右邊比tmp小的數移到左邊空出來的位置 data[left] = data[right] #循環條件是左邊比tmp小,繼續循環,直到找到左邊比tmp大的數,結束循環 while left < right and data[left] <= tmp: left += 1 #把左邊找到的大於tmp的數移到右邊空出來的位置 data[right] = data[left] #當左右相等時,就把tmp放到left和right碰到的位置 data[left] = tmp #mid的值和lef或right值相同,return哪一個均可以 #mid = left # return mid return left #對遞歸函數的裝飾,須要再封裝一層 @cal_time def quik_sort(data): #0及是left,len(data)-1爲right return quick_sort_x(data,0,len(data)-1)
import time,random,copy def cal_time(func): def wrapper(*args,**kwargs): t1 = time.time() ret = func(*args,**kwargs) t2 = time.time() print('time cost: %s from %s'%(t2-t1,func.__name__)) return func return wrapper def quick_sort_x(data,left,right): #這裏的left和right是定義列表data,最少有兩個元素 if left<right: #partition分割函數,mid是放好的元素的下標 mid = partition(data,left,right) #如下相似二分 quick_sort_x(data,left,mid-1) quick_sort_x(data,mid+1,right) #快排的複雜度是O(nlog(n)),這是一個特殊狀況 def partition(data,left,right): #獲取左邊的第一個元素,這裏寫left不能寫零,由於後面須要遞歸 tmp = data[left] #終止條件爲當left和right碰上時,因此左小於右時爲while循環的條件(left和right是下標) while left < right: #循環條件是右邊比tmp大,直到找到右邊比tmp小的數,中止循環 while left < right and data[right] >= tmp: right -= 1 #把找到的右邊比tmp小的數移到左邊空出來的位置 data[left] = data[right] #循環條件是左邊比tmp小,繼續循環,直到找到左邊比tmp大的數,結束循環 while left < right and data[left] <= tmp: left += 1 #把左邊找到的大於tmp的數移到右邊空出來的位置 data[right] = data[left] #當左右相等時,就把tmp放到left和right碰到的位置 data[left] = tmp #mid的值和lef或right值相同,return哪一個均可以 #mid = left # return mid return left #對遞歸函數的裝飾,須要再封裝一層 @cal_time def quik_sort(data): #0及是left,len(data)-1爲right return quick_sort_x(data,0,len(data)-1) #冒泡排序 @cal_time def bubble_sort(li): for i in range(len(li) - 1): exchange = False for j in range(len(li) - i - 1): #升續 if li[j] > li[j+1]: li[j],li[j+1]=li[j+1],li[j] exchange = True #降續 # if li[j] < li[j+1]: # li[j],li[j+1]=li[j+1],li[j] # exchange = True #這裏是指上一趟,值之間沒有發生交換,就退出循環 if not exchange: break data = list(range(5000)) random.shuffle(data) #深度拷貝 data1 = copy.deepcopy(data) data2 = copy.deepcopy(data) #快排和冒泡的比較 quik_sort(data1) bubble_sort(data2) print(data1)
升續:
降續:
排序速度的定義:
通常狀況下快排比冒泡快,快排有遞歸深度的問題,若是深度高的話,須要調整。
1五、堆排序
(1)樹與二叉樹簡介
樹是一種數據結構 好比:目錄結構
樹是一種能夠遞歸定義的數據結構
樹是由n個節點組成的集合:
若是n=0,那這是一棵空樹;
若是n>0,那存在1個節點做爲樹的根節點,其餘節點能夠分爲m個集合,每一個集合自己又是一棵樹。
一些概念
根節點、葉子節點
樹的深度(高度)
樹的度
孩子節點/父節點 子樹
(2)二叉樹
二叉樹:度不超過2的樹(節點最多有兩個叉)
(3)滿二叉樹,徹底二叉樹
(4)二叉樹的存儲方式
鏈式存儲方式
順序存儲方式(列表)
父節點和左孩子節點的編號下標有什麼關係?
0-1 1-3 2-5 3-7 4-9
i ~ 2i+1
父節點和右孩子節點的編號下標有什麼關係?
0-2 1-4 2-6 3-8 4-10
i ~ 2i+2
(5)小結
二叉樹是度不超過2的樹
滿二叉樹與徹底二叉樹
(徹底)二叉樹能夠用列表來存儲,經過規律能夠從父親找到孩子或從孩子找到父親
(6)堆排序
大根堆:一棵徹底二叉樹,知足任一節點都比其孩子節點大
小根堆:一棵徹底二叉樹,知足任一節點都比其孩子節點小
(7)堆排序過程
a、創建堆
b、獲得堆頂元素,爲最大元素
c、去掉堆頂,將堆最後一個元素放到堆頂,此時可經過一次調整從新使堆有序。
d、堆頂元素爲第二大元素。
e、 重複步驟3,直到堆變空。