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

时间:2016-08-04 11:36:57

标签: recursion rust

我已经在Rust中实现了Ramer-Douglas-Peucker线简化算法,并且它可以正确地用于epsilon值> 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]]);
}

1 个答案:

答案 0 :(得分:4)

查看rdp的流程。它是一个递归函数,在dmax > epsilon的条件下递归。因此,当我们逐步完成时,让我们遵循这些变量:

首先,我们将dmax设置为1.0。然后,如果distance > dmaxdmax设置为distance。因此,dmax无法小于1.0。

然后,如果dmax > epsilon,我们会递归。如果epsilon < 1.0

,这将始终

如果我们在wikipedia上查看算法,您会发现dmax应该从0.0开始。

顺便说一句,你可以使用hypot函数使距离函数更好。