一、算法概念
算法:就是一個計算過程,解決問題的方法。
二、遞歸
2.1、遞歸特點
遞歸算法是一種直接或間接調用自身算法的過程,在計算機編程中,它往往使算法的描述簡潔而且易於理解。
遞歸算法解決問題的特點:
(1)遞歸就是在過程或函數裏調用自身。
(2)在使用遞歸策略時,必須有一個明確的遞歸結束條件,稱爲遞歸出口。
(3)遞歸算法解題通常顯得很簡潔,但遞歸算法解題的運行效率較低,所以一般不提倡用遞歸算法設計程序。
(4)在遞歸調用的過程中系統爲每一層的返回點、局部量等開闢了新棧來存儲,遞歸次數過多容易造成棧溢出等。
遞歸的要求
遞歸算法所體現的“重複”一般有三個要求:
(1)每次調用在規模上都有所縮小(通常是減半)。
(2)是相鄰兩次重複之間有緊密的聯繫,前一次要爲後一次做準備(通常前一次的輸出作爲後一次的輸入)。
(3)在問題的規模極小時必須直接給出解答而不再進行遞歸調用,因而每次遞歸調用都是有條件的(以規模未達到直接解答的大小爲條件)無條件遞歸調用將會成爲死循環而不能正常結束。
2.2、簡單的遞歸函數實例:
def recursion(i): #定義函數
print(i)
if i/2 > 1: #判斷遞歸條件,退出
re = recursion(i/2) #遞歸函數自身
print('返回值:',re)
print('上層遞歸值:',i)
return i #返回值
recursion(10)
#運行原理:首先運行函數傳參10給函數,打印10,判斷條件滿足,遞歸
#函數參數值爲(10/2)5,打印i的值5,等遞歸到1.25時,判斷條件不滿
#足後,纔打印上層遞歸的值,此時遞歸的值爲1.25,return遞歸最後一
#層的值1.25,退出最後一層遞歸,繼續一層層退出遞歸,最後返回最上層
#遞歸值結束函數。
'''
10
5.0
2.5
1.25
上層遞歸值: 1.25
返回值: 1.25
上層遞歸值: 2.5
返回值: 2.5
上層遞歸值: 5.0
返回值: 5.0
上層遞歸值: 10
'''
斐波那契數列:就是前兩個數的和爲後一個數的值(0,1,1,2,3,5,8,13…)
def foo(arg1,arg2,stop):
if arg1 == 0:
print(arg1,arg2)
arg3 = arg1 + arg2
print(arg1,arg2,arg3)
if arg3 < stop: #判斷套件不滿足時退出遞歸
foo(arg2,arg3,stop) #遞歸函數,傳送參數arg2,arg3,stop給arg1,arg2,stop
foo(0,1,50)
'''
0 1
0 1 1
1 1 2
1 2 3
2 3 5
3 5 8
5 8 13
8 13 21
13 21 34
21 34 55
'''
利用切片遞歸方式,查找數據:
def twosplit(sourceDate,findData):
sp = int(len(sourceDate)/2) #序列長度
if sourceDate[0] == findData:
print('找到數據:',sourceDate[0])
return 0
else:
if findData in sourceDate[:sp]: #判斷在左邊
print('數據在左邊[%s]' %sourceDate[:sp])
twosplit(sourceDate[:sp],findData) #遞歸函數
elif findData in sourceDate[sp:]: #判斷在右邊
print('數據在右邊[%s]' %sourceDate[sp:])
twosplit(sourceDate[sp:], findData)
else:
print('找不到數據')
if __name__ == '__main__':
data = [1,2,'c',3,4,5,6,7,8,17,26,15,14,13,12,11,'a','b']
#data = list(range(1000000))
twosplit(data,'c')
二位數組,順時針90度數據調換:
a = [[col for col in range(4)] for row in range(4)]
for i in a:print(i) #打印二維數組
print('--------------------')
for lf,rig in enumerate(a): #循環數組,打印數組下標和元素
for cf in range(lf,len(rig)): #從下標數組開始循環到列表長度
tmp = a[cf][lf] #存儲列表元素中的元素
a[cf][lf] = rig[cf]
a[lf][cf] = tmp
print('+++++++++++++++++')
for i in a:print(i)
'''
#另一種方法
for i in range(len(a)):
ai = [a[i][i] for row in range(4)]
print(ai)
'''
2.3、遞歸原理
函數調用時,函數會開一個新棧,在新棧中執行這個函數體中的代碼。
2.3.1、print() 語句在遞歸前
在函數調用前的代碼會依次執行完之後再執行後面的函數調用。
2.3.2、print() 語句在遞歸後
在函數調用後的代碼會等到函數所有調用執行完之後再從裏到外依次執行。
三、二分查找
每次能夠排除掉一半的數據,查找的效率非常高,但是侷限性比較大; 必須是有序列表纔可以使用二分查找。
# 1.非遞歸算法
def binary_search(lis, nun):
left = 0
right = len(lis) - 1
while left <= right: #循環條件
mid = (left + right) // 2 #獲取中間位置,數字的索引(序列前提是有序的)
if num < lis[mid]: #如果查詢數字比中間數字小,那就去二分後的左邊找,
right = mid - 1 #來到左邊後,需要將右變的邊界換爲mid-1
elif num > lis[mid]: #如果查詢數字比中間數字大,那麼去二分後的右邊找
left = mid + 1 #來到右邊後,需要將左邊的邊界換爲mid+1
else:
return mid #如果查詢數字剛好爲中間值,返回該值得索引
return -1 #如果循環結束,左邊大於了右邊,代表沒有找到
lis = [11, 32, 51, 21, 42, 9, 5, 6, 7, 8]
print(lis)
lis.sort()
print(lis)
while 1:
num = int(input('輸入要查找的數:'))
res = binary_search(lis, num)
print(res)
if res == -1:
print('未找到!')
else:
print('找到!')
# 2.遞歸算法
def binary_search(lis, left, right, num):
if left > right: #遞歸結束條件
return -1
mid = (left + right) // 2
if num < lis[mid]:
right = mid -1
elif num > lis[mid]:
left = mid + 1
else:
return mid
return binary_search(lis, left, right, num)
#這裏之所以會有return是因爲必須要接收值,不然返回None
#回溯到最後一層的時候,如果沒有return,那麼將會返回None
lis = [11, 32, 51, 21, 42, 9, 5, 6, 7, 8]
print(lis)
lis.sort()
print(lis)
while 1:
num = int(input('輸入要查找的數:'))
res = binary_search(lis, 0, len(lis)-1,num)
print(res)
if res == -1:
print('未找到!')
else:
print('找到!')