成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何優(yōu)化尾調用

開發(fā)
經(jīng)常看到關于尾遞歸這三個詞,遞歸很多時候,都離不開我們,廢話不多說,這次我們梳理一遍關于遞歸那些事。

 

            [[344640]]

 前言

 

在這里關于遞歸,這里就不贅述了,有興趣的可以去查一查資料。

 

需要了解如何優(yōu)化尾遞歸的話,我們需要從最開始講起。

  • 什么是尾調用
  • 什么是尾遞歸
  • 如何優(yōu)化尾遞歸

尾調用
從字面理解,自然而言就是在函數(shù)的尾部返回一個函數(shù)的調用,通常來說,指的是函數(shù)執(zhí)行的最后一步。

舉個例子👇

  1. const fn = () => f1() || f2() 
  2. // 這里的話, f2函數(shù)有可能是尾調用,f1不可能是尾調用 

為什么f1函數(shù)不是呢,我們看這個函數(shù)的等價形式👇

  1. const fn = function () { 
  2.     const flag = f1() 
  3.     if(flag) { 
  4.         return flag 
  5.     } else { 
  6.         return f2() 
  7.     } 

似乎寫到這里,根據(jù)尾調用定義,我們就明白了,只有f2函數(shù)是在尾部調用。

說到這里,為什么要說尾調用呢?我們事先想一想傳統(tǒng)的遞歸,典型的就是首先執(zhí)行遞歸調用,然后根據(jù)這個遞歸的返回值并結算結果,那么傳統(tǒng)的遞歸缺點有哪些呢👇

  • 效率低,占內存。
  • 如果遞歸鏈過長,可能會stack overflow

那么我們是不是可以做優(yōu)化呢,這就可以涉及上面提到的尾調用,它的原理是啥呢👇

“按照阮一峰老師在es6的函數(shù)擴展中的解釋就是:函數(shù)調用會在內存形成一個“調用記錄”,又稱“調用幀”(call frame),保存調用位置和內部變量等信息。如果在函數(shù)A的內部調用函數(shù)B,那么在A的調用幀上方,還會形成一個B的調用幀。等到B運行結束,將結果返回到A,B的調用幀才會消失。如果函數(shù)B內部還調用函數(shù)C,那就還有一個C的調用幀,以此類推。所有的調用幀,就形成一個“調用棧”(call stack)。
“這里的“調用幀”和“調用棧”,說的應該就是“執(zhí)行環(huán)境”和“調用棧”。因為尾調用時函數(shù)的最后一部操作,所以不再需要保留外層的調用幀,而是直接取代外層的調用幀,所以可以起到一個優(yōu)化的作用。
從上述的描述中,我們視乎可以理解成

  • 它的原理類似于當編譯器檢測到一個函數(shù)調用是尾遞歸時,它會覆蓋當前的活動記錄而不是在函數(shù)棧中創(chuàng)建一個新的調用記錄。
  • 這樣子,我們也可以理解成,不同的語言編譯器或者是解釋器做了尾遞歸優(yōu)化,才讓它不會爆棧。

既然是這樣子的話,尾遞歸的優(yōu)化,取決于瀏覽器,那具體有哪些主流瀏覽器支持呢👇

safari 和火狐,有興趣的可以去了解一下,可以寫個斐波那契數(shù)列數(shù)列驗證一下。

手動優(yōu)化
既然我們知道了,很多瀏覽器對于尾遞歸的優(yōu)化支持的瀏覽器并不多,那你會好奇,當我們使用尾遞歸進行優(yōu)化的時候,依然出現(xiàn)棧溢出的錯誤,那么我們如何解決呢?👇

我在網(wǎng)上看到一個不錯的方案,采用的是蹦床函數(shù)👇

  1. function trampoline(f) { 
  2.   while (f && f instanceof Function) { 
  3.     f = f(); 
  4.   } 
  5.   return f; 

那么如何使用呢👇

我們拿最常見的斐波那契數(shù)列來說吧

  1. function fibonacci(n) { 
  2.   if (n === 0) return 0 
  3.   if (n === 1) return 1 
  4.   return fibonacci(n - 1) + fibonacci(n - 2) 

根據(jù)上面的式子,我們可以將其寫成迭代形式,用一個變量去緩存它的值👇

  1. function fibonacci (n, ac1 = 0, ac2 = 1) { 
  2.     return n <= 1 ? ac2 :fibonacci(n - 1, ac2, ac1 + ac2); 

其實試過的小伙伴,會發(fā)現(xiàn),當你需要求的n足夠大的時候,還是會報錯,類似于下面的錯誤信息👇

  1. // fibonacci(10000) 
  2. Uncaught RangeError: Maximum call stack size exceeded 

這個時候,那么我們如何去優(yōu)化呢?難道真的沒有辦法可以解決了嗎👇

這里得借鑒下別人的思路,我覺得挺不錯的,這里就給出代碼👇

  1. function trampoline(f) { 
  2.   while (f && f instanceof Function) { 
  3.     f = f(); 
  4.   } 
  5.   return f; 

你可以把這個函數(shù)稱之為蹦床函數(shù), 這個函數(shù)的作用就是放回一個新的函數(shù),我們將它們倆結合起來的話,棧溢出的問題似乎就可以解決了👇

  1. // 可以試一試噢 
  2. trampoline(fibonacci (10000)) 

這里的蹦床函數(shù),我是參考別人的寫法,似乎這樣子寫的話,不太行,我個人覺得這樣子可以避免調用棧溢出,實際情況下,這樣子是行不通的,哪里有行不通的,還望指出。

當然了,手動優(yōu)化,可以將遞歸的過程改寫成迭代的過程,就拿斐波那契數(shù)列這題來說,我們可以使用動態(tài)規(guī)劃來完成👇,O(n)完成答案的更新。

  1. // 偽代碼 
  2. F[i] = F[i-1] + F[i-2] 

嗯,將一個尾遞歸函數(shù)轉換成循環(huán)迭代函數(shù),算是手動優(yōu)化一種方式,在我們語言沒有原生支持尾遞歸優(yōu)化,那么可以考慮這種情況。

對于尾遞歸而言,我們需要了解優(yōu)化它的原理,如果有必要的話,將遞歸的形式寫成迭代的形式,通過迭代方式,降低重復值的計算,當然了,這個過程,有時候是比較難的,值得我們去思考。

 

責任編輯:姜華 來源: 前端UpUp
相關推薦

2019-03-26 08:15:45

iOS尾調用Objective-C

2020-05-27 07:38:36

尾遞歸優(yōu)化遞歸函數(shù)

2010-09-17 13:01:44

Python

2009-07-22 07:44:00

Scala尾遞歸

2011-06-07 15:42:25

優(yōu)化URL

2020-04-16 09:44:53

JupyterPython機器學習

2011-06-24 16:44:43

網(wǎng)站優(yōu)化

2012-03-16 16:33:35

視頻會議馬賽克深信服

2020-10-16 09:00:12

前端開發(fā)技術

2009-11-16 13:59:22

Oracle優(yōu)化

2023-10-18 10:38:53

API

2020-10-16 10:40:39

前端性能可視化

2010-01-11 16:31:54

C++優(yōu)化器

2023-03-29 07:36:32

鏈表頭插尾插

2013-09-02 16:04:20

Windows

2024-02-19 08:11:40

C++編程尾返回類型推導

2020-06-16 10:31:13

云計算投資云平臺

2010-05-26 16:09:09

MySQL Repli

2021-08-18 09:37:27

云存儲成本云端

2023-07-24 16:09:58

Kubernetes云計算
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 九九免费视频 | 成人精品视频99在线观看免费 | 欧美成年黄网站色视频 | 欧美精品第三页 | 国产91视频播放 | 国产精品亚洲一区二区三区在线观看 | 超碰人人人人 | a精品视频| 国产免国产免费 | 美日韩免费视频 | 国产欧美日韩二区 | 精品在线观看一区 | 最近中文字幕在线视频1 | 天天干亚洲 | 欧美精品久久久久 | 亚洲a视频| 欧美成人h版在线观看 | 99久久久无码国产精品 | 五月婷婷丁香婷婷 | 成人三级av | 免费视频一区 | 成人黄色在线 | 影音先锋中文字幕在线观看 | 午夜影院在线观看 | 国产精品视频不卡 | 久久四虎 | 成人久久一区 | 天天操夜夜骑 | 免费观看一级特黄欧美大片 | 久草在线影 | 精品视频在线观看 | 日韩一区二区三区av | 久久亚洲一区 | аⅴ资源新版在线天堂 | 国产精品免费福利 | 久久免费国产 | 欧美99久久精品乱码影视 | 国产成年人视频 | 亚洲精选一区二区 | 久久中文视频 | 福利电影在线 |