Recursion 调用此递归函数时如何避免堆栈溢出

Recursion 调用此递归函数时如何避免堆栈溢出,recursion,rust,Recursion,Rust,我已经在Rust中实现了Ramer–Douglas–Peucker线简化算法,它在ε值>1.0时正确工作。但是,任何低于该值的值都会导致堆栈溢出。如何重写函数以避免这种情况 // distance formula pub fn distance(start: &[f64; 2], end: &[f64; 2]) -> f64 { ((start[0] - end[0]).powf(2.) + (start[1] - end[1]).powf(2.)).sqrt()

我已经在Rust中实现了Ramer–Douglas–Peucker线简化算法,它在ε值>1.0时正确工作。但是,任何低于该值的值都会导致堆栈溢出。如何重写函数以避免这种情况

// distance formula
pub fn distance(start: &[f64; 2], end: &[f64; 2]) -> f64 {
    ((start[0] - end[0]).powf(2.) + (start[1] - end[1]).powf(2.)).sqrt()
}

// perpendicular distance from a point to a line
pub fn point_line_distance(point: &[f64; 2], start: &[f64; 2], end: &[f64; 2]) -> f64 {
    if start == end {
        return distance(*&point, *&start);
    } else {

        let n = ((end[0] - start[0]) * (start[1] - point[1]) -
                 (start[0] - point[0]) * (end[1] - start[1]))
            .abs();
        let d = ((end[0] - start[0]).powf(2.0) + (end[1] - start[1]).powf(2.0)).sqrt();
        n / d
    }
}

// Ramer–Douglas-Peucker line simplification algorithm
pub fn rdp(points: &[[f64; 2]], epsilon: &f64) -> Vec<[f64; 2]> {
    let mut dmax = 1.0;
    let mut index: usize = 0;
    let mut distance: f64;
    for (i, _) in points.iter().enumerate().take(points.len() - 1).skip(1) {
        distance = point_line_distance(&points[i],
                                       &*points.first().unwrap(),
                                       &*points.last().unwrap());
        if distance > dmax {
            index = i;
            dmax = distance;
        }
    }
    if dmax > *epsilon {
        let mut intermediate = rdp(&points[..index + 1], &*epsilon);
        intermediate.pop();
        intermediate.extend_from_slice(&rdp(&points[index..], &*epsilon));
        intermediate
    } else {
        vec![*points.first().unwrap(), *points.last().unwrap()]
    }
}

fn main() {
    let points = vec![[0.0, 0.0], [5.0, 4.0], [11.0, 5.5], [17.3, 3.2], [27.8, 0.1]];
    // change this to &0.99 to overflow the stack
    let foo: Vec<_> = rdp(&points, &1.0);
    assert_eq!(foo, vec![[0.0, 0.0], [5.0, 4.0], [11.0, 5.5], [17.3, 3.2]]);
}
//距离公式
发布fn距离(起点:&[f64;2],终点:&[f64;2])->f64{
((start[0]-end[0]).powf(2.)+(start[1]-end[1]).powf(2.).sqrt()
}
//点到线的垂直距离
发布fn点线距离(点:&[f64;2],起点:&[f64;2],终点:&[f64;2])->f64{
如果开始=结束{
返回距离(*&点、*&起点);
}否则{
设n=((结束[0]-开始[0])*(开始[1]-点[1])-
(开始[0]-点[0])*(结束[1]-开始[1]))
.abs();
设d=((end[0]-start[0]).powf(2.0)+(end[1]-start[1]).powf(2.0)).sqrt();
不适用
}
}
//Ramer–Douglas Peucker直线简化算法
发布fn rdp(点:&[[f64;2]],ε:&f64)->Vec{
设mut dmax=1.0;
让mut索引:usize=0;
让mut距离:f64;
在points.iter().enumerate().take(points.len()-1.skip(1)中为(i,){
距离=点\线\距离(&点[i],
&*points.first().unwrap(),
&*points.last().unwrap());
如果距离>dmax{
指数=i;
dmax=距离;
}
}
如果dmax>*ε{
设mut intermediate=rdp(&points[…index+1],&*epsilon);
intermediate.pop();
中间。从_切片扩展_(&rdp(&points[index..,&*epsilon));
中间的
}否则{
vec![*点.first().unwrap(),*点.last().unwrap()]
}
}
fn main(){
让分数=vec![[0.0,0.0]、[5.0,4.0]、[11.0,5.5]、[17.3,3.2]、[27.8,0.1];
//将其更改为&0.99以使堆栈溢出
设foo:Vec=rdp(&points,&1.0);
断言(foo,vec![[0.0,0.0]、[5.0,4.0]、[11.0,5.5]、[17.3,3.2]);
}

查看
rdp
的流程。它是一个递归函数,在
dmax>epsilon
的条件下递归。因此,让我们按照这些变量逐步进行:

首先,我们将
dmax
设置为1.0。然后,如果
distance>dmax
dmax
设置为
distance
。因此,
dmax
不可能小于1.0

然后,如果
dmax>epsilon
,我们递归。如果epsilon<1.0,则始终会发生这种情况

如果我们查看上的算法,您可以看到
dmax
应该从0.0开始


另一方面,您可以使用该函数使距离函数变得更好。

看看
rdp
的流程。它是一个递归函数,在
dmax>epsilon
的条件下递归。因此,让我们按照这些变量逐步进行:

首先,我们将
dmax
设置为1.0。然后,如果
distance>dmax
dmax
设置为
distance
。因此,
dmax
不可能小于1.0

然后,如果
dmax>epsilon
,我们递归。如果epsilon<1.0,则始终会发生这种情况

如果我们查看上的算法,您可以看到
dmax
应该从0.0开始


顺便说一句,您可以使用该函数使距离函数变得更好。

在本
dmax
中,从
0
开始。为什么要用
1.0
启动
dmax
?一般来说,堆栈溢出是一种用户错误:)@MatthieuM。哦,我从来没有怀疑过这是真的。不幸的是,对于我来说,这并不是一个更微妙的错误……在这个
dmax
中,它以
0
开头。为什么要用
1.0
启动
dmax
?一般来说,堆栈溢出是一种用户错误:)@MatthieuM。哦,我从来没有怀疑过这是真的。不幸的是,对我来说,这并不是一个更微妙的错误……好吧,这很尴尬。好吧,这很尴尬。