道格拉斯算法

道格拉斯-普克抽稀算法,是用来对大量冗余的图形数据点进行压缩以提取必要的数据点。

传统的道格拉斯算法是通过递归方式实现的,如:http://blog.csdn.net/cdl2008sky/article/details/7701769

算法的基本思路是:对每一条曲线的首末点虚连一条直线,求所有点与直线的距离,并找出最大距离值dmax ,用dmax与限差D相比:若dmax <D,这条曲线上的中间点全部舍去;若dmax ≥D,保留dmax 对应的坐标点,并以该点为界,把曲线分为两部分,对这两部分重复使用该方法。

传统的道格拉斯-普克算法都是递归实现,然而有时候递归的层次太深的话会出现栈溢出的情况。在此,介绍一种非递归的算法。

改进D-P算法的具体步骤如下:

1、将首末两点加入队列,遍历队列。

2、计算出其它点到以首末点连线的直线的最大距离并和限差进行比较。

3、若大于等于限差,将这个点加入到队列中两点之间,并重新遍历序列,以相邻点作为始末点。若小于限差则将首末点中间点全部删除。

代码如下:

Point.java

package com.lwy.domain;

public class Point {

	private double x;
	private double y;
	public double getX() {
		return x;
	}
	public void setX(double x) {
		this.x = x;
	}
	public double getY() {
		return y;
	}
	public void setY(double y) {
		this.y = y;
	}
	public Point(double x, double y) {
		super();
		this.x = x;
		this.y = y;
	}
}
Douglas.java
<pre name="code" class="java">package com.lwy.douglas;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import com.lwy.domain.Point;

public class Douglas {

	// 存储用于处理的点的List列表
	private List<Point> list = null;

	// 给定的阈值(限差)threshold
	private final double threshold = 1;

	public Douglas(List<Point> list) {
		this.list = list;
	}

	/**
	 * 道格拉斯算法,处理List<Point>序列
	 * 先将首末两点加入points序列中,然后在list序列找出距离首末点连线距离的最大距离值dmax并与阈值进行比较,
	 * 若大于阈值则将这个点加入points序列,重新遍历points序列。否则将两点间的所有点(list)移除。
	 * 
	 * @return 返回经过道格拉斯算法后得到的点的序列
	 */
	public List<Point> douglasPeucker() {
		List<Point> points = new LinkedList<>();
		// 将首末两点加入到序列中
		points.add(this.list.get(0));
		points.add(list.get(list.size() - 1));
		for (int i = 0; i < points.size() - 1; i++) {
			int start = this.list.indexOf(points.get(i));
			int end = this.list.indexOf(points.get(i + 1));
			// 比较是否是相邻点
			if (end - start == 1) {
				continue;
			}
			String value = getMaxDistance(start, end);
			double maxDist = Double.parseDouble(value.split(",")[0]);
			// 大于限差将点加入points序列
			if (maxDist >= threshold) {
				int position = Integer.parseInt(value.split(",")[1]);
				points.add(i + 1, list.get(position));
				// 将循环变量i初始化,即重新遍历points序列
				i = -1;
			} else {
				/**
				 * 将两点间的点全部删除
				 */
				int removePosition = start + 1;
				for (int j = 0; j < end - start - 1; j++) {
					this.list.remove(removePosition);
				}
			}
		}
		return points;
	}

	/**
	 * 根据给定的始末点,计算出距离始末点直线的最远距离和点在list列表中的位置
	 * @param start 遍历list起始点
	 * @param end 遍历list终点
	 * @return maxDiatance + "," + position 返回最大距离+","+在list中位置
	 */
	private String getMaxDistance(int start, int end) {
		double maxDiatance = -1;
		int position = -1;
		double distance = getDistance(this.list.get(start), this.list.get(end));
		for (int i = start; i < end; i++) {
			double firstSide = getDistance(this.list.get(start),
					this.list.get(i));
			if (firstSide < threshold) {
				continue;
			}
			double lastSide = getDistance(this.list.get(end), this.list.get(i));
			if (lastSide < threshold) {
				continue;
			}
			// 使用海伦公式求距离
			double p = (distance + firstSide + lastSide) / 2;
			double dis = Math.sqrt(p * (p - distance) * (p - firstSide)
					* (p - lastSide))
					/ distance;
			if (dis > maxDiatance) {
				maxDiatance = dis;
				position = i;
			}
		}
		return maxDiatance + "," + position;
	}

	// 两点间距离公式
	private double getDistance(Point first, Point last) {
		return Math.sqrt(Math.pow(first.getX() - last.getX(), 2)
				+ Math.pow(first.getY() - last.getY(), 2));
	}

	public static void main(String[] args) {
		Point point0 = new Point(1, 4);
		Point point1 = new Point(2, 3);
		Point point2 = new Point(4, 2);
		Point point3 = new Point(6, 6);
		Point point4 = new Point(7, 7);
		Point point5 = new Point(8, 6);
		Point point6 = new Point(9, 5);
		Point point7 = new Point(10, 10);
		List<Point> list = new ArrayList<>();
		list.add(point0);
		list.add(point1);
		list.add(point2);
		list.add(point3);
		list.add(point4);
		list.add(point5);
		list.add(point6);
		list.add(point7);
		Douglas douglas = new Douglas(list);
		List<Point> points = douglas.douglasPeucker();
		for (int i = 0; i < points.size(); i++) {
			System.out.println("(" + points.get(i).getX() + ","
					+ points.get(i).getY() + ")");
		}
	}
}

结果为:
 
(1.0,4.0)
(4.0,2.0)
(7.0,7.0)
(9.0,5.0)
(10.0,10.0)
 

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
DP道格拉斯算法是一种用于求解组合优化问题的方法,尤其在整数编码决策问题的应用中,该方法能产生快速的算法解决方案。这个算法主要是使用动态规划的概念来解决这种问题。下面我将为您简单介绍一下DP道格拉斯算法的基本思想和使用Python实现的例子。 **DP道格拉斯算法的基本思想** DP道格拉斯算法的核心思想是利用一个或多个变量来存储子问题的解,通过这种方式,我们可以在不重复计算的情况下求解更大的问题。在DP道格拉斯算法中,我们通常使用一个数组或列表来存储子问题的解,并通过这个数组或列表来逐步求解原问题。 **Python实现** 以下是一个简单的DP道格拉斯算法的Python实现,假设我们有一个问题是要在给定的整数列表中找到所有可能的组合,使得它们的和等于给定的目标值。 ```python def douglas_p(lst, target): n = len(lst) dp = [[False] * (target + 1) for _ in range(n)] dp = True for i in range(n): for j in range(i+1, n+1): for k in range(i+1, j+2): if lst[i] <= k and dp[i][k-lst[i]]: dp[j][j-k] = True return dp[-1][-1] ``` 这个函数接受一个整数列表和一个目标值作为输入,返回一个布尔值,表示是否存在一种组合使得所有元素的和等于目标值。这个函数使用了一个二维数组dp来存储子问题的解。初始时,所有元素都被设置为False,除了第一个元素,它的解被设置为True(即初始组合为空)。然后,我们遍历列表中的每个元素,并检查是否存在一种方式可以将这个元素添加到已有的组合中,使得总和等于目标值。如果存在这样的方式,我们就将dp数组中的相应位置设置为True。最后,我们返回dp数组的最后一个元素最后一个位置的值,即是否存在一种组合使得所有元素的和等于目标值。 注意:这个实现只是一个基本的例子,实际应用中可能需要根据具体问题对算法进行适当的修改和优化。此外,对于大规模问题,可能需要使用更高效的算法和数据结构来提高性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值