当前位置: 首页 > 知识库问答 >
问题:

迭代vs递归:计算已知迭代序列中的点位置

尹臻
2023-03-14

我有一个递归函数,它取一个点,递归地计算序列中的下一个点。

看起来有点像这样:

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处点的位置,才能将这些值应用于?

共有1个答案

钱经业
2023-03-14

可以将其视为复数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,在这里,它执行叠加的任意多个组合。