递归的基本原理
Se pra você:
- Recursão é um tema obscuro ou quer entender mais um pouco sobre;
- 尾部呼叫 TCO以便与外星人进行通信;
- 蹦床和补救措施
Então este artigo é pra você。
您可以通过Ruby示例来解释说明形式和解决问题的术语。我们不关心示例,因为它是简单的,因为它是一种不可知论的语言。
Portanto,venha comigo nesta viagem Interminável。
✋
Para Continuar, volte ao topo do post
议程
O que é recursão
在计算机程序中,人们习惯于解决一些重大问题,因为这些问题都是我们使用的功能或方法。
递归是一种极其简单的计算技术,它解决了确定函数和递归执行问题的问题。
这是一个“chama a si mesma”功能,用于解析器计算和连续执行。
Fibo para os íntimos
典型的递归和描述的例子,斐波那契数列,或斐波那契数列,都与确定的位置有关。
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55.........
这是一个有趣的结果:
fib(0) = 0
fib(1) = 1
fib(2) = 1
...
fib(7) = 13
fib(10) = 55
在 Ruby 中可以实现递归的方法:
def fib(position)
return position if position < 2
fib(position - 1) + fib(position - 2)
end
Este código, entretanto, não é Performático。总线上的编号为 10000 (dez mil) na sequencia, o 程序中的多个缓慢点会导致递归冗余。
fib(10)
/ \
fib(9) fib(8)
/ \ / \
fib(8) fib(7) fib(7) fib(6)
/ \ / \ / \
fib(7) fib(6) fib(6) fib(5) fib(6) fib(5)
/ \ / \ / \ / \
fib(6) fib(5) fib(5) fib(4) fib(5) fib(4) fib(5) fib(4)
/ \ / \ / \ / \ / \ / \ / \
...
结果,主要的输入功能、执行速度都趋向于指数形式的渐进,而不是Big-O系列O(2^n)。
可能会减少复杂性吗?
您是否可以在函数中应用技术,或者在递归中使用 apenas uma chamada 递归,或者实现辅助计算?
该技术存在尾调用或尾递归。
尾部呼叫
尾调用或TC是由递归函数和最后的递归函数以及附加计算函数组成的。
这是一个复杂的指数对线性复数,它是简单的循环迭代和输入列表。
Big-O 不是输入的O(n)线性伴奏或渐强的复合体。
Ruby示例:
def fib(position, _current = 0, _next = 1)
return _current if position < 1
fib(position - 1, _next, _current + _next)
end
Portanto,或递归和简化算法的数字:
fib(10, 0, 1)
fib(9, 1, 1)
fib(8, 1, 2)
fib(7, 2, 3)
fib(6, 3, 5)
fib(5, 5, 8)
fib(4, 8, 13)
fib(3, 13, 21)
fib(2, 21, 34)
fib(1, 34, 55)
fib(0, 55, 89)
修复递归的数字,或者重新排序,然后再线性地进行删除。
阿西姆,在TC 的罗达或 Fib com程序上,罗达 SEM TC 的执行速度和指数,速度很快。
✋
Claramente um programa que leva tempo exponencial é péssimo em termos de Performance,não?
# Sem TC
fib(30) # 0.75 segundos
# Com TC
fib(30) # 0.000075 segundos
Voltando ao exemplo de fib(10000), ao rodar com TC, vemos que a execução é muito mais rápida, porém:
recursion/fib.rb:10:in `fib_tc': stack level too deep (SystemStackError)
from recursion/fib.rb:10:in `fib_tc'
from recursion/fib.rb:10:in `fib_tc'
from recursion/fib.rb:10:in `fib_tc'
from recursion/fib.rb:10:in `fib_tc'
from recursion/fib.rb:10:in `fib_tc'
from recursion/fib.rb:10:in `fib_tc'
from recursion/fib.rb:10:in `fib_tc'
from recursion/fib.rb:10:in `fib_tc'
糟糕,堆栈溢出!
在此情况下,首先会发生堆栈和堆栈溢出。
堆栈溢出
执行程序时,会存储数据格式、堆栈的内存,并使用数据保护程序发送数据并使用执行功能。
✋
Há também outra estrutura na programa chamada Heap,que não é uma pilha e tem outras características que vão além do escopo deste artigo。 Para entender recursão, focamos apenas na stack
在功能或方法中使用程序,将其放入(推送)堆栈中。结束一个功能,并通过 cada bado进行远程(流行)操作。
一个新的堆栈框架的功能。如果在终端上递归,则运行时将精确地“弹出”并完成框架,然后进入新的堆栈框架,并在堆栈中添加一些元素。
是否有一些关于如何将计算机内存中的超级密码限制的信息?
Sim,了解堆栈溢出💥🪲,它解释了 Ruby 和 10000 com 尾调用的错误。
✋
10000 的计算是否存在递归解析器无法解决的问题?
冷静,语言的使用技术包括使用 chamada TC com apenas um 堆栈框架,并确保 cada recursiva seja tratada como se fosse uma iteração numloop primitivo。
这是一个关于堆栈框架的参数和功能的操作,可在原始循环中执行任务。结果,新的查马达斯递归地从尾部递归到皮拉的挑衅者。
尾部呼叫优化或TCO 的最新技术。
尾部调用优化
Devido a sua natureza imperativa, e assim como diversas outras linguagens de propósito geral, Ruby não traz supporte nativo a TCO .
总体而言,它的功能是与语言相关的,但它不是命令式的,而是范式功能的。
通过Ruby 和 Ruby 运行时 (YARV) 指令的简单配置,可以实现 TCO 模式,并且可以执行 10000 个扫描周期。
RubyVM::InstructionSequence.compile_option = {
tailcall_optimization: true,
trace_instruction: false
}
def fib(position, _current = 0, _next = 1)
return _current if position < 1
fib(position - 1, _next, _current + _next)
end
# TC com TCO
fib(10000) # 0.02 segundos
太棒了! Com TCO habilitado,uma fib 10000 com tail call é executada em 0.02 segundos!
TCO 技术的价值在于,它可以重复使用和编译器中的工具说明,可以轻松地了解
该技术。
✋
好的,您是否可以在 eu estiver 计划中使用 TCO 并使用语言来支持 TCO?
Trampoline para o resgate.
蹦床
对于蹦床来说,没有任何问题,并且有可能解决。
在情报方面,我们初步完成了一次重复开发,并确定了一个数字前提。
def fib(position, _current = 0, _next = 1)
return _current if position < 1
###################################
#### Devemos evitar isso!!!!!! ####
###################################
fib(position - 1, _next, _current + _next)
end
Premissa dois,ao invés de retornar uma chamada recursiva ditamente,e se a retornarmos encapsulada em uma estrutura de função anônima queguarda contexto para ser executada em outro contexto?
Sim、tipo uma 关闭或 lambda para os mais atentos
在 Ruby 中,使用了lambda表达式。
def fib(position, _current = 0, _next = 1)
return _current if position < 1
lambda do
fib(position - 1, _next, _current + _next)
end
end
Se chamarmos result = fib(0),由于短路 ( position < 1) 的原因,或返回方法0。
mas se chamarmos result = fib(10),或者返回到递归,mas sim 或返回到函数 anônima (lambda)。
这是一种方法,是一种最终的方法,可以在堆栈中完成,也可以在方法中流行。
Como lambdas Guardam contexto, se chamarmos result.call, a lambda é executada com o contexto anterior, que pode retornar o número Final (caso entre no Short-Circuit) or outra lambda com o novo contexto.
E assim,ficamos em 循环 até termos 或 valor Final,enquanto 或 retorno atual continuar sendo uma lambda。是否有什么问题?
Sim,嗯,循环!
result = fib(10000)
while result.is_a?(Proc)
result = result.call
end
puts result
输出(um número mesmo muito grande):
33644764876431783266621612005107543310302148460680063906564769974680081442166662368155595513633734025582065332680836159373734790483865268263040892463056431887354544369559827491606602099884183933864652731300088830269235673613135117579297437854413752130520504347701602264758318906527890855154366159582987279682987510631200575428783453215515103870818298969791613127856265033195487140214287532698187962046936097879900350962302291026368131493195275630227837628441540360584402572114334961180023091208287046088923962328835461505776583271252546093591128203925285393434620904245248929403901706233888991085841065183173360437470737908552631764325733993712871937587746897479926305837065742830161637408969178426378624212835258112820516370298089332099905707920064367426202389783111470054074998459250360633560933883831923386783056136435351892133279732908133732642652633989763922723407882928177953580570993691049175470808931841056146322338217465637321248226383092103297701648054726243842374862411453093812206564914032751086643394517512161526545361333111314042436854805106765843493523836959653428071768775328348234345557366719731392746273629108210679280784718035329131176778924659089938635459327894523777674406192240337638674004021330343297496902028328145933418826817683893072003634795623117103101291953169794607632737589253530772552375943788434504067715555779056450443016640119462580972216729758615026968443146952034614932291105970676243268515992834709891284706740862008587135016260312071903172086094081298321581077282076353186624611278245537208532365305775956430072517744315051539600905168603220349163222640885248852433158051534849622434848299380905070483482449327453732624567755879089187190803662058009594743150052402532709746995318770724376825907419939632265984147498193609285223945039707165443156421328157688908058783183404917434556270520223564846495196112460268313970975069382648706613264507665074611512677522748621598642530711298441182622661057163515069260029861704945425047491378115154139941550671256271197133252763631939606902895650288268608362241082050562430701794976171121233066073310059947366875
🔑 Ponto-chave
E com isto, amigues, temos a técnica Trampoline : um Loop primitivo não-recursivo que fica chamando outra função escrita de forma recursiva mas que retorna uma lambda com contexto, até chegar ao valor Final .
估计,SEM TCO,大约10000 倍,大约 0.04 秒,结果是 TCO 和 SEM 导致堆栈溢出。
Incrível,não? Agora não há desculpas para não escrever uma função de modo recursivo em linguagens que não trazem support a TCO 😛
结论
就直觉而言,特拉泽尔古斯认为自己没有重复的主题。这些想法与学术背景重叠,但在学术背景中却存在一些困难。
想要了解有关教学或重复的内容,请参阅相关评论或相关信息。
参考资料
https://twitter.com/leandronsp/status/1672043065001869312
https://twitter.com/JeffQuesado/status/1671954585987022882
https://en.wikipedia.org/wiki/Fibonacci_sequence
https://en.wikipedia.org/wiki/Recursion
https://www.geeksforgeeks.org/stack-data-structure/
https://en.wikipedia.org/wiki/Tail_call
https://en.wikipedia.org/wiki/Trampoline_(computing)
https://nithinbekal.com/posts/ruby-tco/
https://www.bigocheatsheet.com/
https://ruby-doc.org/core-3.1.0/RubyVM/InstructionSequence.html#method-c-compile_option


