首頁 後端開發 Python教學 如何使用Python實作斐波那契Fibonacci函數

如何使用Python實作斐波那契Fibonacci函數

Mar 10, 2017 pm 01:58 PM
python

這篇文章主要介紹瞭如何使用Python實現斐波那契Fibonacci函數相關資料,需要的朋友可以參考下

Fibonacci斐波那契數列,很簡單,就是一個遞歸嘛,學任何程式語言可能都會做一下這個。

最近在玩Python,在粗略的看了一下Learning Python和Core Python之後,偶然發現網路上有個貼文Python程式設計師的演化寫的很有意思。於是打算仿照一篇,那篇貼文用了十餘種方法完成一個階乘函數,我在這裡會用九種不同的風格寫出一個Fibonacci函數。

要求很簡單,輸入n,輸出第n個Fibonacci數,n為正整數

下面是這九種不同的風格:

1)第一次寫程式的Python程式設計師:

def fib(n):
  return nth fibonacci number
登入後複製

說明:
第一次寫程式的人往往遵循人類語言的語法而不是程式語言的語法,就拿我一個程式設計很猛的哥們來說,他寫的第一個判斷閏年的程序,裡面直接是這麼寫的:如果year是閏年,輸出year是閏年,否則year不是閏年。

2)剛學Python不久的的C程式設計師:

#
def fib(n):#{
 if n<=2 :
  return 1;
 else:
  return fib(n-1)+fib(n-2);
#}
登入後複製

說明:
剛接觸Python時,用縮排而非大括號的方式來劃分程式塊這種方式我是很不適應的,而且每個語句後面沒有結束符,所以每次寫完一個Python函數之後乾的第一件事一般就是一邊註釋大括號,一邊加上漏掉的冒號。

3)懶散的Python程式設計師:

def fib(n):
  return 1 and n<=2 or fib(n-1)+fib(n-2)
登入後複製

說明:
看了Learning Python之後,才知道Python沒有三元操作符? ,不過鑑於Python裡bool值比較特殊(有點像C,非零即真,非空即真),再加上Python的邏輯語句也是支援短路求值(Short-Circuit Evaluation)的,這就可以寫出一個仿?語句出來。

4)更懶的Python程式設計師:

 fib=lambda n:1 if n<=2 else fib(n-1)+fib(n-2)
登入後複製

說明:
lambda關鍵字我曾在C#和Scheme裡面用過,Python裡面的lambda比C#裡簡便,很像Scheme裡的用法,所以很快就適應了。在用Python Shell宣告一些小函數時常用這種寫法。

5)剛學完資料結構的Python程式設計師:

def fib(n):
 x,y=0,1
 while(n):
  x,y,n=y,x+y,n-1
 return x
登入後複製

說明:
前面的Fibonacci函數都是樹形遞歸的實現,就算學一點演算法就應該知道這種遞歸的低效了。這裡從樹形遞歸改為對應的迭代可以把效率提升不少。
Python的元組賦值特性是我很喜歡的一個東東,這玩意可以把程式碼簡化不少。舉個例子,以前的tmp=a;a=b;b=tmp;可以直接用一句a,b=b,a實現,既簡潔又明了。

6)正在修SICP課程的Python程式設計師:

def fib(n):
  def fib_iter(n,x,y):
   if n==0 : return x
   else : return fib_iter(n-1,y,x+y)

  return fib_iter(n,0,1)
登入後複製

說明:
在這裡我使用了Scheme語言中很常見的尾遞歸(Tail-recursion)寫法。 Scheme裡面沒有迭代,但可以用不變量和尾遞歸來模擬迭代,從而達到相同的效果。不過我還不清楚Python有沒有對尾遞歸做相對應的優化,回頭查一查。
PS:看過SICP的同學,一眼就能看出,這個程式其實就是SICP第一章裡的例子。

7)好耍小聰明的Python程式設計師:

fib=lambda n,x=0,y=1:x if not n else f(n-1,y,x+y)
登入後複製

說明:
基本的邏輯和上面的例子一樣,都是尾遞歸寫法。主要的差別就是利用了Python提供的預設參數和三元操作符,從而把程式碼簡化至一行。至於預設參數,學過C++的同學都知道這玩意,至於C#4.0也引進了這東東。

8)剛修完線性代數的Python程式設計師:

def fib(n):
 def m1(a,b):
  m=[[],[]]
  m[0].append(a[0][0]*b[0][0]+a[0][1]*b[1][0])
  m[0].append(a[0][0]*b[0][1]+a[0][1]*b[1][1])
  m[1].append(a[1][0]*b[0][0]+a[1][1]*b[1][0])
  m[1].append(a[1][0]*b[1][0]+a[1][1]*b[1][1])
  return m
 def m2(a,b):
  m=[]
  m.append(a[0][0]*b[0][0]+a[0][1]*b[1][0])
  m.append(a[1][0]*b[0][0]+a[1][1]*b[1][0])
  return m
 return m2(reduce(m1,[[[0,1],[1,1]] for i in range(n)]),[[0],[1]])[0]
登入後複製

說明:
這段程式碼就不像之前的程式碼那樣清晰了,所以先介紹下原理(需要一點線性代數知識):
先看一下之前的迭代版本的Fibonacci函數,很容易可以發現存在一個變換:y->x, x +y->y。換一個角度,就是[x,y]->[y,x+y]。
在這裡,我宣告一個二元向量[x,y]T,它透過一個變換得到[y,x+y]T,可以很容易得到變換矩陣是[[1,0],[1, 1]],也就是說:[[1,0],[1,1]]*[x,y]T=[y,x+y]T
設二元矩陣A=[[1, 0],[1,1]],二元向量x=[0,1]T,容易知道Ax的結果就是下一個Fibonacci數值,即:
Ax=[fib(1),fib(2) ]T
亦有:
Ax=[fib(2),fib(3)]T
………………
以此類推,可以得到:

#
Aⁿx=[fib(n),fib(n-1)]T
登入後複製

也就是說可以透過對二元向量[0,1]T進行n次A變換,從而得到[fib(n),fib(n+1 )]T,從而得到fib(n)。

在這裡我定義了一個二元矩陣的相乘函數m1,以及一個在二元向量上的變換m2,然後利用reduce操作完成一個連乘操作得到Aⁿx,最後得到fib (n)。

9)準備參加ACM比賽的Python程式設計師:

#
 def fib(n):
 lhm=[[0,1],[1,1]]
 rhm=[[0],[1]]
 em=[[1,0],[0,1]]
 #multiply two matrixes
 def matrix_mul(lhm,rhm):
  #initialize an empty matrix filled with zero
  result=[[0 for i in range(len(rhm[0]))] for j in range(len(rhm))]
  #multiply loop
  for i in range(len(lhm)):
   for j in range(len(rhm[0])):
    for k in range(len(rhm)):
     result[i][j]+=lhm[i][k]*rhm[k][j]
  return result
 
 def matrix_square(mat):
  return matrix_mul(mat,mat)
 #quick transform
 def fib_iter(mat,n):
  if not n:
   return em
  elif(n%2):
   return matrix_mul(mat,fib_iter(mat,n-1))
  else:
   return matrix_square(fib_iter(mat,n/2))
 return matrix_mul(fib_iter(lhm,n),rhm)[0][0]
登入後複製

說明:

看过上一个fib函数就比较容易理解这一个版本了,这个版本同样采用了二元变换的方式求fib(n)。不过区别在于这个版本的复杂度是lgn,而上一个版本则是线性的。

这个版本的不同之处在于,它定义了一个矩阵的快速求幂操作fib_iter,原理很简单,可以类比自然数的快速求幂方法,所以这里就不多说了。

PS:虽然说是ACM版本,不过说实话我从来没参加过那玩意,毕竟自己算法太水了,那玩意又太高端……只能在这里YY一下鸟~

python中,最基本的那种递归(如下fib1)效率太低了,只要n数字大了运算时间就会很长;而通过将计算的指保存到一个dict中,后面计算时直接拿来使用,这种方式成为备忘(memo),如下面的fib2函数所示,则会发现效率大大提高。

在n=10以内时,fib1和fab2运行时间都很短看不出差异,但当n=40时,就太明显了,fib1运行花了35秒,fab2运行只花费了0.00001秒。
n=40时,输出如下:

jay@jay-linux:~/workspace/python.git/py2014$ python fibonacci.py 
2014-10-16 16:28:35.176396
fib1(40)=102334155
2014-10-16 16:29:10.479953
fib2(40)=102334155
2014-10-16 16:29:10.480035
登入後複製

这两个计算Fibonacci数列的函数,如下:https://github.com/smilejay/python/blob/master/py2014/fibonacci.py

import datetime

def fib1(n):
  if n == 0:
    return 0
  elif n == 1:
    return 1
  else:
    return fib1(n - 1) + fib1(n - 2)
 
known = {0: 0, 1: 1}
 
def fib2(n):
  if n in known:
    return known[n]
 
  res = fib2(n - 1) + fib2(n - 2)
  known[n] = res
  return res

if __name__ == &#39;__main__&#39;:
  n = 40
  print(datetime.datetime.now())
  print(&#39;fib1(%d)=%d&#39; % (n, fib1(n)))
  print(datetime.datetime.now())
  print(&#39;fib2(%d)=%d&#39; % (n, fib2(n)))
  print(datetime.datetime.now())
登入後複製

后记:

由于刚学习Python没多久,所以对其各种特性的掌握还不够熟练。与其说是我在用Python写程序,倒不如说我是在用C,C++,C#或是Scheme来写程序。至于传说中的Pythonic way,我现在还没有什么体会,毕竟还没用Python写过什么真正的程序。
Learning Python和Core Python都是不错的Python入门书籍,前者更适合没有编程基础的人阅读。
Python是最好的初学编程入门语言,没有之一。所以它可以取代Scheme成为MIT的计算机编程入门语言。

以上是如何使用Python實作斐波那契Fibonacci函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

PHP和Python:解釋了不同的範例 PHP和Python:解釋了不同的範例 Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

在PHP和Python之間進行選擇:指南 在PHP和Python之間進行選擇:指南 Apr 18, 2025 am 12:24 AM

PHP適合網頁開發和快速原型開發,Python適用於數據科學和機器學習。 1.PHP用於動態網頁開發,語法簡單,適合快速開發。 2.Python語法簡潔,適用於多領域,庫生態系統強大。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

PHP和Python:深入了解他們的歷史 PHP和Python:深入了解他們的歷史 Apr 18, 2025 am 12:25 AM

PHP起源於1994年,由RasmusLerdorf開發,最初用於跟踪網站訪問者,逐漸演變為服務器端腳本語言,廣泛應用於網頁開發。 Python由GuidovanRossum於1980年代末開發,1991年首次發布,強調代碼可讀性和簡潔性,適用於科學計算、數據分析等領域。

vs code 可以在 Windows 8 中運行嗎 vs code 可以在 Windows 8 中運行嗎 Apr 15, 2025 pm 07:24 PM

VS Code可以在Windows 8上運行,但體驗可能不佳。首先確保系統已更新到最新補丁,然後下載與系統架構匹配的VS Code安裝包,按照提示安裝。安裝後,注意某些擴展程序可能與Windows 8不兼容,需要尋找替代擴展或在虛擬機中使用更新的Windows系統。安裝必要的擴展,檢查是否正常工作。儘管VS Code在Windows 8上可行,但建議升級到更新的Windows系統以獲得更好的開發體驗和安全保障。

visual studio code 可以用於 python 嗎 visual studio code 可以用於 python 嗎 Apr 15, 2025 pm 08:18 PM

VS Code 可用於編寫 Python,並提供許多功能,使其成為開發 Python 應用程序的理想工具。它允許用戶:安裝 Python 擴展,以獲得代碼補全、語法高亮和調試等功能。使用調試器逐步跟踪代碼,查找和修復錯誤。集成 Git,進行版本控制。使用代碼格式化工具,保持代碼一致性。使用 Linting 工具,提前發現潛在問題。

notepad 怎麼運行python notepad 怎麼運行python Apr 16, 2025 pm 07:33 PM

在 Notepad 中運行 Python 代碼需要安裝 Python 可執行文件和 NppExec 插件。安裝 Python 並為其添加 PATH 後,在 NppExec 插件中配置命令為“python”、參數為“{CURRENT_DIRECTORY}{FILE_NAME}”,即可在 Notepad 中通過快捷鍵“F6”運行 Python 代碼。

sublime怎麼運行代碼python sublime怎麼運行代碼python Apr 16, 2025 am 08:48 AM

在 Sublime Text 中運行 Python 代碼,需先安裝 Python 插件,再創建 .py 文件並編寫代碼,最後按 Ctrl B 運行代碼,輸出會在控制台中顯示。

See all articles