遞歸算法
遞歸,就是在運行的過程中調用自己。
構成遞歸需具備的條件:
- 子問題須與原始問題爲同樣的事,且更爲簡單;
- 不能無限制地調用本身,須有個出口,化簡爲非遞歸狀況處理。
在數學和計算機科學中,遞歸指由一種(或多種)簡單的基本情況定義的一類對象或方法,並規定其他所有情況都能被還原爲其基本情況。
遞歸應用
遞歸算法一般用於解決三類問題:
(1)數據的定義是按遞歸定義的。(例如:Fibonacci函數)
(2)問題解法按遞歸算法實現。
這類問題雖則本身沒有明顯的遞歸結構,但用遞歸求解比迭代求解更簡單,如Hanoi問題。
(3)數據的結構形式是按遞歸定義的。
如二叉樹、廣義表等,由於結構本身固有的遞歸特性,則它們的操作可遞歸地描述。
設計遞歸算法的步驟:
1.確定遞歸公式
2.確定邊界(終了)條件
遞歸的缺點
遞歸算法解題相對常用的算法如普通循環等,運行效率較低。因此,應該儘量避免使用遞歸,除非沒有更好的算法或者某種特定情況,遞歸更爲適合的時候。在遞歸調用的過程當中系統爲每一層的返回點、局部量等開闢了棧來存儲。遞歸次數過多容易造成棧溢出等。
簡單遞歸問題舉例
- 斐波納契數列(Fibonacci Sequence),又稱黃金分割數列。
1、1、2、3、5、8、13、21…
Fib(0) = 1,Fib(1) = 1。
對所有n > 1的整數:
Fib(n) = (Fib(n-1) + Fib(n-2))
【斐波那契】
n = int(input())
def Fib(n):
if n == 0 or n == 1:
return 1
else:
return Fib(n-1)+Fib(n-2)
# 輸出
for i in range (n):
print (Fib(i),end=' ')
- 階乘
1!= 1
對所有n > 1的整數:
n! = (n * (n-1)!)
【階乘】
n = int(input())
def Fact(n):
if n == 1:
return 1
else:
return n*Fact(n-1)
# 輸出
print (Fact(n))
- 漢諾塔問題
已知有三根針分別用A, B, C表示,在A中從上到下依次放n個從小到大的盤子。
現要求把所有的盤子從A針全部移到C針,移動規則是:可以使用B臨時存放盤子,每次只能移動一塊盤子,而且每根針上不能出現大盤壓小盤,找出移動次數最小的方案。
A,B,C三個盤子,分別爲初始位,過渡位,目標位:
(1)將最上面的n-1個圓盤從初始位移動到過渡位
(2)將初始位的最底下的一個圓盤移動到目標位
(3)將過渡位的n-1個圓盤移動到目標位
【漢諾塔問題】
count = 0
def hanoi(n,start,end,mid):
global count
if n == 1:
print("{}:{}->{}".format(n,start,end))
count += 1
else:
hanoi(n-1,start,mid,end)
print("{}:{}->{}".format(n,start,end))
count += 1
hanoi(n-1,mid,end,start)
hanoi(3,"A","C","B")
print(count)
【輸出結果】
1:A->C
2:A->B
1:C->B
3:A->C
1:B->A
2:B->C
1:A->C
7
- 上臺階有多少種走法:
樓梯有n階臺階,上樓可以一步上1階,也可以一步上2階,計算共有多少種不同的走法.
設n階臺階的走法數爲f(n)
n=1 時:有1種走法
n=2 時:有2種走法
n>2時: f(n-1)+f(n-2)
【上臺階問題】
def Up(n):
if n == 1:
return 1
elif n == 2:
return 2
else:
return Up(n-1)+Up(n-2)
print(Up(4))
- 遞歸法求數組最大值:
數組爲空:返回0
數組長度爲1:返回這個值
數組長度大於1:比較第一個值和剩餘元素的最大值(調用)
【數組最大值】
def max_num(lists):
if lists == []:
return 0
elif len(lists) == 1:
return lists[0]
else:
if lists[0] > max_num(lists[1:]):
return lists[0]
else:
return max_num(lists[1:])
print(max_num([1, 3, 4, 2]))
- 求累加值:1+2+3+…+n
【累加值】
def add(n):
if n == 1:
return n
else:
return n+add(n-1)
print (add(3))
- 楊輝三角
遞歸求楊輝三角第i行,第j列的值
【楊輝三角求值及輸出】
# 楊輝三角
def yang(i,j):
if i==j or j==1:
return 1
return yang(i-1,j-1)+yang(i-1,j)
# 輸出一個n行的楊輝三角
def Outyang(n):
for i in range(1,n+1):
for j in range(1,i+1):
print (yang(i,j),end=' ')
print('')
Outyang(5)
【輸出】
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
- 迴文串
長度爲1:返回True
長度大於1:
判斷:最外層兩個是否相同
不同:返回False
相同:內移一層(調用)
【判斷是否爲迴文串】
def isHuiWen(str):
if(len(str) <2):
return True
elif str[0] != str[-1]:
return False
else:
return isHuiWen(str[1:-1])
str = input("請輸入一個字符串:")
if isHuiWen(str):
print("該字符串爲迴文字符串")
else:
print("該字符串不是迴文")
- 字符串的全排列
原文鏈接:https://blog.csdn.net/qq_42015869/article/details/79996227
全排列:
1、列表只有一個元素[a],它的全排列只有a。
2、列表有兩個元素[a, b],它的全排列爲[a, b], [b, a]:
{ 將第一個元素a固定,對b進行全排列得到[a, b]。
將第一個元素與第二個元素交換得到[b, a]。
將b固定,對a進行全排列,得到[b, a] }
3、列表有三個元素[a, b, c]
{ 將a固定,對bc進行全排列{ 將b固定,對c全排列[abc]。交換bc,將c固定對b進行全排列[acb] }
交換ab,[b, a, c] 對ac進行全排列{ … }
… …}
4、列表有n個元素,將第一個元素固定,對剩下n - 1個元素進行全排列。
將第一個元素依此與其他元素交換,對每次交換後剩下的n-1個元素進行全排列。
5、對剩下的n - 1個元素全排列,同上,固定後對n - 2排列。
6、直到數組數量爲1,全排列就是它自己,完成一次排列。
【字符全排列】
def perm(data, begin, end):
if begin == end: # 遞歸結束條件,當交換到最後一個元素的時候不需要交換,1的全排列還是1。
print(data) # 打印一次排列完成後的數組。
else:
j = begin
for i in range(begin, end): # 從begin到end全排列。
data[i], data[j] = data[j], data[i]
perm(data, begin + 1, end)
data[i], data[j] = data[j], data[i] # 遞歸完成後,交換回原來的位置。
arr = [1, 2, 3, 4, 5]
perm(arr, 0, len(arr))
- 二分法查找
def searchNum(ls, num, lower=0, upper=None):
if upper is None:
upper = len(ls) - 1
mid = (lower + upper) // 2
if mid == 0 and num != ls[0]:
return "不存在"
if mid == len(ls) - 1 and num != ls[-1]:
return "不存在"
if num == ls[mid]:
return mid, ls[mid]
elif num < ls[mid]:
return searchNum(ls, num, lower, mid)
else:
return searchNum(ls, num, mid + 1, upper)
L = [5, 8, 9, 12, 17, 19, 20, 22]
n = 8
result = searchNum(L, n)
print(result)