兩個基礎知識點:遞歸和時間復雜度
遞歸
遞歸函數的特點:自己調用自己,有結束條件,看下面例子:
def fun1(x):
"""無結束條件,報錯"""
print(x)
fun1(x-1)
def fun2(x):
"""結束條件為錯誤條件,報錯"""
if x>0:
print(x)
fun2(x+1)
def fun3(x):
"""打印倒序"""
if x>0:
print(x)
fun3(x-1)
def fun4(x):
"""打印正序"""
if x > 0:
fun4(x-1)
print(x)
fun3(7)
fun4(7)
結果:
7
6
5
4
3
2
1
*******
1
2
3
4
5
6
7
時間復雜度
用來評估算法運行效率的東西:
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')
while n > 1:
'''時間復雜度:O(log2n)或者O(logn)'''
print(n)
n = n // 2
小結:
- 時間復雜度是用來估算一個算法運行時間的標准
- 一般說來,時間復雜度高的要比時間復雜度低的算法慢
- 常見的復雜度按效率排行:
O(1) < O(logn) <O(n) <O(nlogn) < O(n^2) < O(n^2 logn) < O(n^3)
那么如何一樣判斷時間復雜度?
- 循環減半的過程,O(logn)
- 幾次循環就是n的幾次方的復雜度
列表查找
- 輸入:列表或者待查找元素
- 輸出:元素下標或者未查到的元素
順序查找
從元素的第一個開始,按順序進行查找,直到找到為止
二分查找
從有序列表的候選區data[0:n]開始,通過對待查找的值與候選區中間值的比較,可以使候選區減少一半。
import time
#定義一個計算運行時間的裝飾器
def cal_time(func):
def wrapper(*args,**kwargs):
t1 = time.time()
res = func(*args,**kwargs)
t2 = time.time()
print('%s:%s'%(func.__name__,t2-t1))
return res
return wrapper
#順序查找
@cal_time
def linear_search(data_set,value):
for i in range(len(data_set)):
if data_set[i] == value:
return i
#二分查找
@cal_time
def bin_search(data_set,value):
low = 0
high = len(data_set) - 1
while low <= high:
mid = (low + high) // 2
if data_set[mid] == value:
return mid
elif data_set[mid] < value:
low = mid + 1
else:
high = mid - 1
ret = linear_search(list(range(100000)),99999)
ret2 = bin_search(list(range(100000)),99999)
但有個問題:理論上順序查找的時間復雜度為O(n),二分查找的為O(logn),看結果二分查找的結果為一個科學記數法,相差2個量級.
linear_search:0.009849071502685547
bin_search:1.5974044799804688e-05
列表排序
將無序列表變為有序列表
low逼三人組:冒泡、選擇、插入
之前寫過:http://www.cnblogs.com/ccorz/p/5581066.html
冒泡
序列中,相鄰的兩個元素比較大小,如果前面的比后面的元素大,那么交換位置,以此類推...
import random
data = list(range(10000))
random.shuffle(data)
def bubbel_sort(data):
for i in range(len(data) - 1):
for j in range(len(data) - i - 1):
if data[j] > data[j+1]:
data[j], data[j+1] = data[j+1], data[j]
bubbel_sort(data)
print(data)
冒泡的優化:
如果排序執行了一趟數據沒有交換,那么說明列表已經是有序狀態,可以直接結束算法:
def bubbel_sort(data):
for i in range(len(data) - 1):
exchange = False
for j in range(len(data) - i - 1):
if data[j] > data[j+1]:
data[j], data[j+1] = data[j+1], data[j]
exchange = True
if not exchange:
break
選擇
遍歷一趟,選擇最小的數放到第一個位置,接着遍歷剩下的序列,選擇其中最小的,放到剩下序列的第一個位置,如此循環.
import random
data = list(range(1000))
random.shuffle(data)
def select_sort(data):
for i in range(len(data) - 1):
min_loc = i
for j in range(i + 1, len(data)):
if data[j] < data[min_loc]:
min_loc = j
if min_loc != i:
data[i], data[min_loc] = data[min_loc], data[i]
select_sort(data)
print(data)
插入排序
列表被分為有序區和無序區兩個部分,並且最初有序區只有一個元素.
import random
data = list(range(1000))
random.shuffle(data)
def insert_sort(data):
for i in range(1,len(data)):
tmp = data[i]
j = i - 1
while j >= 0 and data[j] > tmp:
data[j+1] = data[j]
j -= 1
data[j+1] = tmp
insert_sort(data)
print(data)
快速排序(簡稱快排)
好些的算法里最快的,快的排序算法中最好寫的。
思路:
- 取第一個元素,是這個元素(P)歸位(對的位置)
- 列表被P元素分成兩部分
- 遞歸這兩部分列表,以此類推
總結一句話就是:先整理,后遞歸
import sys, random
#解除python默認遞歸次數的限制
sys.setrecursionlimit(10000)
data = list(range(1000))
random.shuffle(data)
def quick_sort(data, left, right):
if left < right:
mid = partition(data, left, right)
quick_sort(data, left, mid - 1)
quick_sort(data, mid + 1, right)
def partition(data, left, right):
tmp = data[left]
while left < right:
while left < right and data[right] >= tmp:
right -= 1
data[left] = data[right]
while left < right and data[left] <= tmp:
left += 1
data[right] = data[left]
data[left] = tmp
return left
quick_sort(data, 0, len(data) - 1)
print(data)
堆排序
二叉樹
滿二叉樹是指這樣的一種二叉樹:除最后一層外,每一層上的所有結點都有兩個子結點。在滿二叉樹中,每一層上的結點數都達到最大值,即在滿二叉樹的第k層上有2k-1個結點,且深度為m的滿二叉樹有2m-1個結點。
完全二叉樹是指這樣的二叉樹:除最后一層外,每一層上的結點數均達到最大值;在最后一層上只缺少右邊的若干結點。

二叉樹的數據存儲

二叉樹總結
- 二叉樹是不超過2個節點的樹
- 滿二叉樹是完全二叉樹,完全二叉樹不一定是滿二叉樹
- 完全二叉樹可以用列表來存儲,通過規律可以從父親找到孩子,或從孩子找到父親
堆
大根堆:一顆完全二叉樹,滿足任何一節點都比其子節點大
小根堆:一顆完全二叉樹,滿足任何一節點都比其子節點小

堆排序

堆排序的過程:
- 建立堆
- 得到堆頂元素,假設為最大元素
- 去掉堆頂元素,將最后一個元素放到堆頂,此時可以通過一次調整,重新使堆有序
- 堆頂元素為第二大元素
- 重復步驟三
代碼:
import sys, random
sys.setrecursionlimit(10000)
data = list(range(100))
random.shuffle(data)
def sift(data,low,high):
'''堆整理,選出最大的元素'''
i = low
j = 2*i+1
k = j +1
tmp = data[i]
while j <= high:
if j < high and data[j] < data[k]:
j+=1
if tmp < data[j]:
data[i]=data[j]
i=j
j=2*i+1
else:
break
data[i]=tmp
def heap_sort(data):
n = len(data)
for i in range(n//2-1,-1,-1):
sift(data,i,n-1)
for i in range(n-1,-1,-1):
data[0],data[i]=data[i],data[0]
sift(data,0,i-1)
heap_sort(data)
print(data)
out:
[0, 1, 2, 3, 12, 5, 4, 6, 7, 8, 25, 9, 10, 11, 17, 23, 13, 73, 29, 14, 15, 19, 40, 28, 44, 64, 30, 27, 18, 16, 21, 70, 22, 20, 31, 24, 34, 32, 33, 26, 35, 36, 39, 46, 37, 41, 38, 42, 86, 45, 43, 51, 62, 47, 49, 75, 72, 54, 50, 48, 57, 63, 68, 56, 87, 60, 67, 59, 55, 78, 58, 61, 69, 52, 53, 80, 83, 65, 89, 66, 94, 91, 71, 82, 92, 90, 77, 81, 74, 84, 95, 76, 85, 88, 93, 79, 96, 98, 97, 99]
