我有一个递归函数,它取一个点,递归地计算序列中的下一个点。
看起来有点像这样:
var DECAY = 0.75;
var LENGTH = 150;
var ANGLE = 0.52;
getNextPoint(0, 0, ANGLE, LENGTH);
function getNextPoint (x, y, a, l) {
l *= DECAY;
a += ANGLE;
var x1 = x - Math.cos(a) * l;
var y1 = y - Math.sin(a) * l;
//We now have 2 points, draw lines etc.
getNextPoint(x1, y1, a, l);
}
给定已知迭代,如何计算一个点(或两个连续点)?
我知道给定迭代的角度和长度值可以通过以下方式轻松计算:
var a = ANGLE * iteration;
var l = LENGTH * Math.pow(DECAY, iteration);
但我仍然需要知道迭代1处点的位置,才能将这些值应用于?
可以将其视为复数z=xi*y是你的观点<代码>b=cos(a)*l i*sin(a)*l是一些参数,而<代码>c=cos(角度)*衰减i*sin(角度)*衰减是一个常数。
最初,您有z0=0和b0=c*长度/衰减
。在每个递归中
b(k+1) = b(k)*c
z(k+1) = z(k) - b
所以你有
b1 = b0*c = c^2*LENGTH/DECAY
z1 = z0-b1 = -b1 = -c^2*LENGTH/DECAY
b2 = b1*c = c^3*LENGTH/DECAY
z2 = z1-b2 = -(c^2+c^3)*LENGTH/DECAY
⋮
zn = -(c^2+c^3+⋯+c^(n+1))*LENGTH/DECAY
如果你问Wolfram Alpha它会告诉你
c^2+c^3+⋯+c^(n+1) = c^2*(c^n - 1)/(c - 1)
如果你乘以复共轭,你可以使分母为实数。然后你就可以把整个过程转换成一个实数公式。那么让我们写
c = cr + i*ci cr = cos(ANGLE)*DECAY ci = sin(ANGLE)*DECAY
d = c^n = dr + i*di dr = cos(n*ANGLE)*pow(DECAY, n) di = …
那么我们有
c^2*(d - 1)*(cr - i*ci - 1)/((cr + i*ci - 1)*(cr - i*ci - 1))
= ((cr + i*ci)*(cr + i*ci)*(dr + i*di - 1)*(cr - i*ci - 1)) /
((cr - 1)*(cr - 1)*ci*ci)
= ((cr^3*dr + cr*ci^2*dr - cr^2*ci*di - ci^3*di - cr^3 - cr*ci^2
- cr^2*dr + ci^2*dr + 2*cr*ci*di + cr^2 - ci^2) +
(cr^2*ci*dr + ci^3*dr + cr^3*di + cr*ci^2*di - cr^2*ci - ci^3
- 2*cr*ci*dr - cr^2*di + ci^2*di + 2*cr*ci))/((cr - 1)*(cr - 1)*ci*ci)
xn = -(cr^3*dr + cr*ci^2*dr - cr^2*ci*di - ci^3*di - cr^3 - cr*ci^2
- cr^2*dr + ci^2*dr + 2*cr*ci*di + cr^2 - ci^2) /
((cr - 1)*(cr - 1)*ci*ci) * LENGTH / DECAY
yn = -(cr^2*ci*dr + ci^3*dr + cr^3*di + cr*ci^2*di - cr^2*ci - ci^3
- 2*cr*ci*dr - cr^2*di + ci^2*di + 2*cr*ci) /
((cr - 1)*(cr - 1)*ci*ci) * LENGTH / DECAY
分子的展开式来自我的CAS;很可能你可以写得更短一些,但我不想手动将这四个术语相乘来尝试。
下面是一个工作示例来演示所有这些:
var ctxt = document.getElementById("MvG1").getContext("2d");
var sin = Math.sin, cos = Math.cos, pow = Math.pow;
var DECAY = 0.75;
var LENGTH = 150;
var ANGLE = 0.52;
var cr = cos(ANGLE)*DECAY, ci = sin(ANGLE)*DECAY;
var cr2 = cr*cr, ci2 = ci*ci, cr3 = cr2*cr, ci3 = ci2*ci;
var f = - LENGTH / DECAY / ((cr - 1)*(cr - 1)*ci*ci)
ctxt.beginPath();
ctxt.moveTo(100,450);
for (var n = 0; n < 20; ++n) {
var da = pow(DECAY, n), dr = cos(n*ANGLE)*da, di = sin(n*ANGLE)*da;
var xn, yn;
xn = (cr3*dr + cr*ci2*dr - cr2*ci*di - ci3*di - cr3 - cr*ci2
- cr2*dr + ci2*dr + 2*cr*ci*di + cr2 - ci2)*f;
yn = (cr2*ci*dr + ci3*dr + cr3*di + cr*ci2*di - cr2*ci - ci3
- 2*cr*ci*dr - cr2*di + ci2*di + 2*cr*ci)*f;
console.log([xn,yn]);
ctxt.lineTo(0.1*xn + 100, 0.1*yn + 450);
}
ctxt.stroke();
<canvas id="MvG1" width="300" height="500"></canvas>
如果说在任何地方都使用递归,那么可以使用for循环,对吗?如果递归通常比较慢,那么将其用于循环迭代的技术原因是什么? 如果总是可以将递归转换为for循环,那么有经验法则吗?
所以我在研究树遍历算法。例如,在K-d树遍历中,我们的目标是遍历节点直至叶子。这与其说是一个树搜索,不如说是一个根到叶的遍历。 在这种情况下,递归解决方案就足够了。但是,在C等语言中,递归调用函数需要将值推送到堆栈上,并在堆栈帧之间跳跃等。标准的递归方法类似于: 因此,考虑到二叉树有一个明确的上界(我相信这也可以扩展到其他树类型),以迭代方式执行此遍历是否更有效: 二叉树的最大高度是它的节点数,而
前面几节介绍了两个可以方便地用递归与迭代实现的函数。本节要比较递归与迭代方法,介绍为什么程序员在不同情况下选择不同方法。 递归与迭代都是基于控制结构:迭代用重复结构,而递归用选择结构。递归与迭代都涉及重复:迭代显式使用重复结构,而递归通过重复函数调用实现重复。递归与迭代都涉及终止测试:迭代在循环条件失败时终止,递归在遇到基本情况时终止。使用计数器控制重复的迭代和递归都逐渐到达终止点:迭代一直修改计
问题内容: 我正在编写一个递归函数,其目的是迭代pList文件。我的代码是 但是当我调用函数“ HashMapper((Map)((Map)entry).keySet());”时。我有一个例外 java.util.HashMap $ HashMap条目不能转换为java.util.Map 我不知道如何调用函数以及如何将Hashmap条目转换为Map 问题答案: 入境确实不是。它是,因此您可以根据需
我有两种不同的方法,一种是用迭代法计算第n个元素的斐波那契序列,另一种是用递归法。 程序示例如下所示: 我试图找出哪种方法更快。我得出的结论是,对于较小数量的数字,递归速度更快,但随着第n个元素的值增加,递归速度变慢,迭代速度变快。以下是三个不同n的三个不同结果: 示例#1(n=10) 示例#2(n=20) 示例#3(n=30) 我真正想知道的是,为什么迭代突然变得更快,递归变得更慢。如果我错过了
我在scheme中构建了一个递归函数,它将在一些输入上重复给定的函数f,n次。 我需要用尾递归构建这个函数的迭代版本,如果我正确理解尾递归,我认为我做得对。 我的问题是,这真的是迭代的吗?我相信我已经使用尾部递归正确地构建了它,但从技术上讲,它仍然将一系列操作推迟到count=0,在这里,它执行叠加的任意多个组合。