一、 算法是什么?
算法是指解題方案的准確而完整的描述,是一系列解決問題的清晰指令,算法代表着用系統的方法描述解決問題的策略機制。也就是說,能夠對一定規范的輸入,在有限時間內獲得所要求的輸出。如果一個算法有缺陷,或不適合於某個問題,執行這個算法將不會解決這個問題。不同的算法可能用不同的時間、空間或效率來完成同樣的任務。一個算法的優劣可以用空間復雜度與時間復雜度來衡量。
二、 時間復雜度:
時間復雜度是用來估計算法運行時間的一個式子(單位)
一般來說*,時間復雜度高的算法比復雜度低的算法慢
常見時間復雜度單位:效率從上到下變低,
O(1) 簡單的一次運算
O(logn) 循環減半
O(n) 一次循環
O(nlogn) 一個循環加一個循環減半
O(n^2) 兩個循環
O(n^2logn)
O(n^3)
如何一眼判斷時間復雜度?
循環減半的過程àO(logn)
幾次循環就是n的幾次方的復雜度
三、 空間復雜度
空間復雜度是用來評估算法內存占用大小的單位
空間換時間:如果需要增快算法的速度,需要的空間會更大
四、python實現常見的算法
1、冒泡(交換)排序
原理:列表中兩個相鄰的數,如果前一個數比后一個數大,就做交換。一共需要遍歷列表的次數是len(lst)-1
時間復雜度:O(n^2)
def bubble_sort(lst): for i in range(len(lst)-1): # 這是需要循環遍歷多少次 for j in range(len(lst)-i-1): # 每次數組中的無序區 if lst[j] >lst[j+1]: lst[j],lst[j+1] = lst[j+1],lst[j] lst = [1, 2, 44, 3, 5] bubble_sort(lst) print(lst)
優化:如果在循環的時候,有一次沒有進行交換,就表示數列中的數據已經是有序的
時間復雜度:最好情況是0(n),只遍歷一次,一般情況和最壞情況都是O(n^2)
def bubble_sort(lst): for i in range(len(lst)-1): # 這是需要循環遍歷多少次 change = False # 做一個標志變量 for j in range(len(lst)-i-1): # 每次數組中的無序區 if lst[j] >lst[j+1]: lst[j],lst[j+1] = lst[j+1],lst[j] change = True # 每次遍歷,如果進來排序的話,就會改變change的值 if not change: # 如果change沒有改變,那就表示當前的序列是有序的,直接跳出循環即可 return lst = [1, 2, 44, 3, 5] bubble_sort(lst) print(lst)
2、選擇排序
原理:每次遍歷找到當下數組最小的數,並把它放到第一個位置,下次遍歷剩下的無序區
def select_sort(lst): for i in range(len(lst) - 1): # 當前需遍歷的次數 min_loc = i # 當前最小數的位置 for j in range(i+1, len(lst)): # 無序區 if lst[j] < lst[min_loc]: # 如果有更小的數 min_loc = j # 最小數的位置改變 if min_loc != i: lst[i], lst[min_loc] = lst[min_loc], lst[i] # 把最小數和無序區第一個數交換交換 lst = [1, 2, 44, 3, 5] select_sort(lst) print(lst)
3、插入排序
原理:列表分為有序區和無序區,有序區是一個相對有序的序列,認為一開始的時候有序區有一值,每次從無序區選擇一個值,放到有序區,直到無序區為空
def insert_sort(lst): for i in range(1,len(lst)): # 從1開始遍歷表示無序區從1開始,有序區初始有一個值 tmp = lst[i] # tmp表示拿到的無序區的第一張牌 j = i - 1 # j表示有序區的最后一個值 while j >= 0 and lst[j] > tmp: # 當有序區有值,並且有序區的值比無序區拿到的值大就一直循環 lst[j+1] = lst[j] # 有序區的值往后移 j -= 1 # 找到上一個有序區的值,然后再循環 lst[j+1] = tmp # 跳出循環之后,只有j+1的位置是空的,要把當下無序區的值放到j+1的位置 lst = [1, 2, 44, 3, 5] insert_sort(lst) print(lst)
二分插入:實際上並沒有優化的效果
def insert_sort(lst): for i in range(1, len(lst)): left = 0 right = i - 1 tmp = lst[i] while left <= right: mid = (left + right) / 2 if tmp >= lst[mid]: left = mid + 1 if tmp < lst[mid]: right = mid - 1 for j in range(i - 1, left - 1, -1): # [i-1,left] lst[j + 1] = lst[j] lst[left] = tmp return lst
4、快速排序
思路:取第一個元素,讓它歸位,就是放到一個位置,使它左邊的都比它小,右邊的都比它大,然后遞歸(先歸位,后遞歸)
時間復雜度:O(nlog(n))
最壞情況:
最壞情況下的事件復雜度是O(n2)
標志數的左邊或者右邊只有一個數
解決方法:不要找第一個元素,隨機找一個元素
def parttion(lst, left, right): i = left j = right tmp = lst[i] # 把此次循環的標志數存起來 while i < j: while i < j and lst[j] > tmp: # 先從右邊開始找比標志數小的,有的話跳出循環 j -= 1 lst[i] = lst[j] # 跳出循環之后,把這個比標志數小的值放到標志數的位置 while i < j and lst[i] < tmp: # 左邊的排序方法和右邊一樣 i += 1 lst[j] = lst[i] lst[i] = tmp # 整個排序結束之后,把一開始的標志數放回空位 return i def quick_sort(lst, left, right): if left < right: # 至少有兩個元素 p = parttion(lst, left, right) quick_sort(lst, left, p-1) quick_sort(lst, p+1, right) lst = [1, 2, 44, 3, 5] quick_sort(a, 0, 4) print(lst)