概念
算法(Algorithm):一個計算過程,解決問題的方法算法
時間複雜度與空間複雜度
時間複雜度數據結構
一個算法的優劣能夠用時間複雜度與空間複雜度來衡量。dom
一般討論算法的複雜度:一、問題規模相同 二、機器配置相同ide
經常使用大O表示法表示時間複雜性,注意它是某一個算法的時間複雜性。函數
如何判斷一個算法的時間複雜度post
- 循環減半的過程>>> O(logn)
- 幾回循環就是N的幾回方的複雜度
經常使用的時間複雜度(按效率排序)優化
O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n2logn)<O(n3)ui
空間複雜度spa
- 用來評估算法內存佔用大小的一個式子
- 算法快總要付出點代價的,利用"空間"來換取"時間"
列表查找
指定從一個列表的全部元素中,查找指定的元素3d
一、順序查找(利用Python內置函數index,in操做,for循環機制均可實現)
二、二分查找(注:前提列表是有序的)
二分查找又稱爲半查找, 由上圖定義low(最小數索引)high(最大數索引)mid(折半數索引)
需求:按照上圖找到數字3
- 既然是二分,每一次循環問題規模相應的要減半。mid=(low + high) // 2
- 若是val(查找數) < mid,即在這個列表二分的左邊,high = mid - 1
- 若是val(查找數) > mid,即反之,low = mid + 1

def bin_search(data_list, val): low = 0 # 最小數下標 high = len(data_list) - 1 # 最大數下標 while low <= high: mid = (low + high) // 2 # 中間數下標 if data_list[mid] == val: # 若是中間數下標等於val, 返回 return mid elif data_list[mid] > val: # 若是val在中間數左邊, 移動high下標 high = mid - 1 else: # 若是val在中間數右邊, 移動low下標 low = mid + 1 return # val不存在, 返回None ret = bin_search(list(range(1, 10)), 3) print(ret)
冒泡排序
冒泡:由於越大的元素會經由交換慢慢「浮」到數列的頂端,故名。
利用相鄰元素比較並進行位置的互換...
需求:一個打亂的列表,進行有效的排序
相鄰兩個值進行比較,將較大的值放在右側,依次比較!(排序好的便再也不比較)

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] li = list(range(10)) random.shuffle(li) # 打亂列表 bubble_sort(li) print(li)

def bubble_sort(li): for i in range(len(li) - 1): # 無需在乎最後一個數 go = 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] go = True if not go: return li = list(range(1000)) random.shuffle(li) # 打亂列表 bubble_sort(li) print(li)
選擇排序
選擇:
- 選擇第一個值的索引賦值給特殊變量,而後循環其餘索引並進行值的比較,若是循環的值 < 特殊變量對應的值,那麼將當前值的索引放入變量中,繼續向後比較
- 選擇第二個值的索引賦值給特殊變量,...
- ...

def select_sort(li): for i in range(len(li) - 1): index = i # 選擇一個數 for j in range(i+1, len(li)): # 與i+1以後的每個數比較 if li[j] < li[index]: # 若是以後的每個數小於標識表明的最小數 index = j # 一直在選擇最小數 li[i], li[index] = li[index], li[i] # 改變位置 li = list(range(10)) random.shuffle(li) select_sort(li) print(li)
插入排序
插入:
- 列表被分爲有序區和無序區兩個部分。最初有序區只有一個元素。
- 每次從無序區選擇一個元素,插入到有序區的位置,直到無序區變空

import random def insert_sort(li): for i in range(1, len(li)): # 從下標1開始 tmp = li[i] # 拿出無序區第一個數 j = i - 1 # 有序區最大數的下標 while j >= 0 and tmp < li[j]: # 條件: 下標j要大於等於0 和 拿出的數小於有序區的最大數 li[j+1] = li[j] # 下標j對應的數要日後挪動一個位置 j = j - 1 # 有序區下一個元素繼續比較 li[j+1] = tmp # tmp從新到本身該到的位置 li = list(range(100)) random.shuffle(li) insert_sort(li) print(li)
快速排序
import random def insert_sort(li): for i in range(1, len(li)): # 從下標1開始 tmp = li[i] # 拿出無序區第一個數 j = i - 1 # 有序區最大數的下標 while j >= 0 and tmp < li[j]: # 條件: 下標j要大於等於0 和 拿出的數小於有序區的最大數 li[j+1] = li[j] # 下標j對應的數要日後挪動一個位置 j = j - 1 # 留出一個位置給tmp li[j+1] = tmp # tmp從新到本身該到的位置 li = list(range(100)) random.shuffle(li) insert_sort(li) print(li
快速:
- 取一個元素P(第一個元素),使元素P歸位
- 列表被P分紅倆部分,左邊都比P小,右邊都比P大
- 遞歸完成排序

# 降序排列 def quick_sort(li, left, right): if left < right: mid = partition(li, left, right) quick_sort(li, mid + 1, right) quick_sort(li, left, mid - 1) def partition(li, left, right): tmp = li[left] # 取出最左邊的數 while left < right: # 若是 left 與 right 值相等 表示tmp找到正確下標 while left < right and li[right] <= tmp: # 和右邊的數比較 right -= 1 li[left] = li[right] while left < right and li[left] >= tmp: # 和左邊的數比較 left += 1 li[right] = li[left] li[left or right] = tmp # tmp到達指定位置 return left or right # 返回tmp下標 data = list(range(10)) random.shuffle(data) quick_sort(data, 0, len(data)-1) print(data)

# 升序排列 def quick_sort(li, left, right): i = left j = right if i >= j: return li tmp = li[i] while i < j: while i < j and li[j] >= tmp: j -= 1 li[i] = li[j] while i < j and li[i] <= tmp: i += 1 li[j] = li[i] li[i] = tmp quick_sort(li, left, j-1) quick_sort(li, i+1, right) return li data = list(range(10)) random.shuffle(data) quick_sort(data, 0, len(data)-1) print(data)
堆排序
前傳:樹與二叉樹簡介
- 樹是一種數據結構 好比:目錄結構
- 樹是一種能夠遞歸定義的數據結構
- 樹是由n個節點組成的集合:
若是n=0,那這是一棵空樹;
若是n>0,那存在1個節點做爲樹的根節點,其餘節點能夠分爲m個集合,每一個集合自己又是一棵樹。
二叉樹:度不超過2的樹(節點最多有兩個叉)
- 滿二叉樹
- 徹底二叉樹
- (徹底)二叉樹能夠用列表來存儲,經過規律能夠從父親找到孩子或從孩子找到父親
堆
- 大根堆:一棵徹底二叉樹,知足任一節點都比其孩子節點大
- 小根堆:一棵徹底二叉樹,知足任一節點都比其孩子節點小
那麼,堆有必定的規律,若是這個堆是這樣的呢
堆排序過程:
- 創建堆
- 獲得堆頂元素,爲最大元素
- 去掉堆頂,將堆最後一個元素放到堆頂,此時可經過一次調整從新使堆有序
- 堆頂元素爲第二大元素
- 重複步驟3,直到堆變空
那麼依託於這個過程,寫一下代碼

import random def sift(data, low, high): """ 建堆 :param data: :param low: :param high: :return: """ i = low # 堆的最高位置 j = 2 * i + 1 # 找左孩子 tmp = data[i] # 最高位置對應數值 while j <= high: # 孩子是否存在於樹內, 一直往下找 if j+1 <= high and data[j] < data[j+1]: # 若是有右孩子而且右孩子比左孩子大 j = j+1 # j指向右孩子 if data[j] > tmp: # 若是孩子比父親大 data[i] = data[j] # 孩子填充到父親的空位 i = j # 孩子成爲新父親, 父親成了孩子 j = 2 * i + 1 # 到下一層的新孩子 else: break data[i] = tmp # 最高領導放到父親位置 def heap_sort(data): n = len(data) # 標識 data 的長度 # 創建好堆 for i in range(n//2-1, -1, -1): sift(data, i, n-1) # 出數 for i in range(n-1, -1, -1): # i指向堆的最後 data[0], data[i] = data[i], data[0] # 領導退休, 刁民上位 sift(data, 0, i-1) # 調整出新領導 data = list(range(100)) random.shuffle(data) heap_sort(data) print(data)
歸併排序,希爾排序
更新中...