《算法技术手册》一3.5.4 解决方案

简介: 本节书摘来华章计算机《算法技术手册》一书中的第3章 ,第3.5.4节, George T.Heineman Gary Pollice Stanley Selkow 著 杨晨 曹如进 译 译更多章节内容可以访问云栖社区“华章计算机”公众号查看。

3.5.4 解决方案

如果手动计算凸包,你应该可以很轻松地处理好各种极端情况。但是如果需要用计算机语言来描叙每一个步骤,我们可能会觉得比较困难。Graham扫描算法的关键点在于计算和最低点的极角大小。一旦计算并且排序之后,算法只需要遍历所有的点,不断地构建凸包并且根据新发现的信息调整结构即可。代码见例3-1。
例3-1:Graham扫描算法的实现
public class NativeGrahamScan implements IConvexHull {

public IPoint[] compute(IPoint[] pts) {
    int n = pts.length;
    if (n < 3) {
        returnpts;
    }
    // 如果最后一个点不是最低点,
    // 那么找到最低点,然后和数组中最后一个点交换
    int lowest = 0;
    double lowestY = pts[0].getY();
    for (inti = 1; i < n; i++) {
        if (pts[i].getY() < lowestY) {
            lowestY = pts[i].getY();
            lowest = i;
        }
    }
    if (lowest != n - 1) {
        IPoint temp = pts[n - 1];
        pts[n - 1] = pts[lowest];
        pts[lowest] = temp;
    }

    // 将pts[0...n-2]按照和pts[n-1]的极角按照从大到小降序排列
    new HeapSort<IPoint>().sort(pts, 0, n - 2,
                                new ReversePolarSorter(pts[n - 1]));
   
    // 有三个点一定在凸包上,它们分别是:
    // 极角最小点pts[n-2]、最低点pts[n-1]还有极角最大点p[0]
    // 初始化凸包,从pts[n-2]和pts[n-1]开始
    DoubleLinkedList<IPoint> list = new DoubleLinkedList<IPoint>();
    list.insert(pts[n - 2]);
    list.insert(pts[n - 1]);
    // 先处理多点共线的情况
    double firstAngle = Math.atan2(pts[0].getY() - lowest, 
                                   pts[0].getX() - pts[n - 1].getX());
    double lastAngle = Math.atan2(pts[n - 2].getY() - lowest, 
                                  pts[n - 2].getX() - pts[n - 1].getX());
    if (firstAngle == lastAngle) {
        return new IPoint[]{pts[n - 1], pts[0]};
    }

    // 顺序访问每个点,删掉不正确的点
    // 一定会出现某个点"向右转",
    // 所以这个while循环必然能够结束
    for (int i = 0; i < n - 1; i++) {
        while (isLeftTurn(list.last().prev().value(), 
                          list.last().value(),
                          pts[i])) {
            list.removeLast();
        }

        // 将下一个点加入凸包中
        list.insert(pts[i]);
    }

    // 最后一个点是重复的,所以我们只需要从最低的点开始取n-1个点即可
    IPoint hull[] = new IPoint[list.size() - 1];
    DoubleNode<IPoint> ptr = list.first().next();
    intidx = 0;
    while (idx < hull.length) {
      hull[idx++] = ptr.value();
      ptr = ptr.next();
    }

    return hull;
}
/** 使用共线性检查来确定左拐 */
public static boolean isLeftTurn(IPoint p1, IPoint p2, IPoint p3) {
    return (p2.getX() - p1.getX()) * (p3.getY() - p1.getY()) -
           (p2.getY() - p1.getY()) * (p3.getX() - p1.getX()) > 0;
}

}

/* 排序类。按照和指定点的极角值降序排列 /
class ReversePolarSorter implements Comparator {

/** 存储用于比较的指定点的x、y坐标 */
final double baseX;
final double baseY;

/** ReversePolarSorter将所有点和指定点比较 */
public ReversePolarSorter(IPoint base) {
    this.baseX = base.getX();
    this.baseY = base.getY();
}

public int compare(IPoint one, IPoint two) {
    if (one == two) { return 0; }

    // 确保使用atan2方法来计算极角,
    // 这个办法可行是因为当前点的y值永远大于指定点的y值
    double oneY = one.getY();
    double twoY = two.getY();
    double oneAngle = Math.atan2(oneY - baseY, one.getX() - baseX);
    double twoAngle = Math.atan2(twoY - baseY, two.getX() - baseX);

    if (oneAngle > twoAngle) { return -1;}
    else if (oneAngle < twoAngle) { return +1; }
    
    // 如果角度相同,那么就比较y值,确保凸包算法能够得到正确的值
    if (oneY > twoY) { return -1; }
    else if (oneY < twoY) { return +1; }

    return 0;
}

}
如果整个点集(n > 2)的所有点都在同一条线上,那么在这种特殊情况下,凸包就只是首尾两端的点。在这种情况下计算出来的凸包可能会包含多个共线的连续点,因为算法中并没有逻辑去试图删除这些共线的点。

相关文章
|
29天前
|
边缘计算 算法 计算机视觉
寻求算法模型迁移技术协助
yolo模型(目标检测、关键点检测)向边缘计算装置(瑞芯微、比特大陆等平台)进行迁移量化时,做到精度损失最低、帧率保持最优。
|
2月前
|
机器学习/深度学习 运维 算法
大模型开发:描述一种用于异常检测的技术或算法。
LOF算法是一种无监督异常检测技术,通过比较数据点局部密度识别离群点。它计算每个点的局部离群因子得分,得分高则异常可能性大。主要步骤包括:距离度量、k近邻搜索、计算局部可达密度和LOF得分,然后设定阈值识别异常点。适用于入侵检测、故障检测等场景,Python中可使用scikit-learn库实现。
20 1
|
7天前
|
JavaScript 前端开发 算法
【JavaScript技术专栏】使用JavaScript实现常见算法
【4月更文挑战第30天】本文介绍了如何使用JavaScript实现常见算法,包括排序、搜索和图算法。首先,通过JavaScript的`sort`方法讨论了排序算法,以快速排序为例展示了自定义排序的实现。接着,探讨了二分查找这一高效的搜索算法,并提供了实现代码。最后,解释了深度优先搜索(DFS)图算法,并给出了在JavaScript中的实现。理解并运用这些算法能有效提升编程能力。
|
13天前
|
人工智能 达摩院 算法
什么是优化技术?给算法小白同学的快速讲解和上手文
本文作者用一个曾经小白学习的视角,来讲解什么是优化问题,以及要如何用这个优化技术。
47759 0
|
21天前
|
算法
R语言使用随机技术差分进化算法优化的Nelson-Siegel-Svensson模型
R语言使用随机技术差分进化算法优化的Nelson-Siegel-Svensson模型
|
25天前
|
人工智能 算法 搜索推荐
淘宝人生2的AIGC技术应用——虚拟人写真算法技术方案
淘宝人生2的AIGC技术应用——虚拟人写真算法技术方案
36 0
|
27天前
|
SQL 人工智能 自然语言处理
NL2SQL基础系列(2):主流大模型与微调方法精选集,Text2SQL经典算法技术回顾七年发展脉络梳理
NL2SQL基础系列(2):主流大模型与微调方法精选集,Text2SQL经典算法技术回顾七年发展脉络梳理
NL2SQL基础系列(2):主流大模型与微调方法精选集,Text2SQL经典算法技术回顾七年发展脉络梳理
|
2月前
|
算法 安全
金石原创 |【分布式技术专题】「分布式技术架构」一文带你厘清分布式事务协议及分布式一致性协议的算法原理和核心流程机制(Paxos篇)
金石原创 |【分布式技术专题】「分布式技术架构」一文带你厘清分布式事务协议及分布式一致性协议的算法原理和核心流程机制(Paxos篇)
53 1
金石原创 |【分布式技术专题】「分布式技术架构」一文带你厘清分布式事务协议及分布式一致性协议的算法原理和核心流程机制(Paxos篇)
|
2月前
|
算法 调度
金石原创 |【分布式技术专题】「分布式技术架构」一文带你厘清分布式事务协议及分布式一致性协议的算法原理和核心流程机制(上篇)
金石原创 |【分布式技术专题】「分布式技术架构」一文带你厘清分布式事务协议及分布式一致性协议的算法原理和核心流程机制(上篇)
59 1
|
2月前
|
机器学习/深度学习 算法 计算机视觉
利用深度学习算法实现图像风格转换技术探究
本文将通过深入分析深度学习算法在图像处理领域的应用,探讨如何利用神经网络实现图像风格转换技术。通过研究不同风格迁移算法的原理和实现方式,揭示其在艺术创作、图像编辑等领域的潜在应用和挑战。