《算法技术手册》一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)的所有点都在同一条线上,那么在这种特殊情况下,凸包就只是首尾两端的点。在这种情况下计算出来的凸包可能会包含多个共线的连续点,因为算法中并没有逻辑去试图删除这些共线的点。

相关文章
|
10月前
|
人工智能 运维 算法
基于 C# 深度优先搜索算法的局域网集中管理软件技术剖析
现代化办公环境中,局域网集中管理软件是保障企业网络高效运行、实现资源合理分配以及强化信息安全管控的核心工具。此类软件需应对复杂的网络拓扑结构、海量的设备信息及多样化的用户操作,而数据结构与算法正是支撑其强大功能的基石。本文将深入剖析深度优先搜索(Depth-First Search,DFS)算法,并结合 C# 语言特性,详细阐述其在局域网集中管理软件中的应用与实现。
230 3
|
7月前
|
监控 算法 安全
基于 C# 基数树算法的网络屏幕监控敏感词检测技术研究
随着数字化办公和网络交互迅猛发展,网络屏幕监控成为信息安全的关键。基数树(Trie Tree)凭借高效的字符串处理能力,在敏感词检测中表现出色。结合C#语言,可构建高时效、高准确率的敏感词识别模块,提升网络安全防护能力。
180 2
|
6月前
|
运维 监控 算法
基于 Java 滑动窗口算法的局域网内部监控软件流量异常检测技术研究
本文探讨了滑动窗口算法在局域网流量监控中的应用,分析其在实时性、资源控制和多维分析等方面的优势,并提出优化策略,结合Java编程实现高效流量异常检测。
265 0
|
9月前
|
监控 算法 JavaScript
基于 JavaScript 图算法的局域网网络访问控制模型构建及局域网禁止上网软件的技术实现路径研究
本文探讨局域网网络访问控制软件的技术框架,将其核心功能映射为图论模型,通过节点与边表示终端设备及访问关系。以JavaScript实现DFS算法,模拟访问权限判断,优化动态策略更新与多层级访问控制。结合流量监控数据,提升网络安全响应能力,为企业自主研发提供理论支持,推动智能化演进,助力数字化管理。
222 4
|
9月前
|
存储 监控 算法
内网监控桌面与 PHP 哈希算法:从数据追踪到行为审计的技术解析
本文探讨了内网监控桌面系统的技术需求与数据结构选型,重点分析了哈希算法在企业内网安全管理中的应用。通过PHP语言实现的SHA-256算法,可有效支持软件准入控制、数据传输审计及操作日志存证等功能。文章还介绍了性能优化策略(如分块哈希计算和并行处理)与安全增强措施(如盐值强化和动态更新),并展望了哈希算法在图像处理、网络流量分析等领域的扩展应用。最终强调了构建完整内网安全闭环的重要性,为企业数字资产保护提供技术支撑。
261 2
|
10月前
|
存储 监控 算法
基于 Python 哈希表算法的局域网网络监控工具:实现高效数据管理的核心技术
在当下数字化办公的环境中,局域网网络监控工具已成为保障企业网络安全、确保其高效运行的核心手段。此类工具通过对网络数据的收集、分析与管理,赋予企业实时洞察网络活动的能力。而在其运行机制背后,数据结构与算法发挥着关键作用。本文聚焦于 PHP 语言中的哈希表算法,深入探究其在局域网网络监控工具中的应用方式及所具备的优势。
321 7
|
10月前
|
运维 监控 算法
基于 Python 迪杰斯特拉算法的局域网计算机监控技术探究
信息技术高速演进的当下,局域网计算机监控对于保障企业网络安全、优化资源配置以及提升整体运行效能具有关键意义。通过实时监测网络状态、追踪计算机活动,企业得以及时察觉潜在风险并采取相应举措。在这一复杂的监控体系背后,数据结构与算法发挥着不可或缺的作用。本文将聚焦于迪杰斯特拉(Dijkstra)算法,深入探究其在局域网计算机监控中的应用,并借助 Python 代码示例予以详细阐释。
255 6
|
10月前
|
存储 算法 物联网
解析局域网内控制电脑机制:基于 Go 语言链表算法的隐秘通信技术探究
数字化办公与物联网蓬勃发展的时代背景下,局域网内计算机控制已成为提升工作效率、达成设备协同管理的重要途径。无论是企业远程办公时的设备统一调度,还是智能家居系统中多设备间的联动控制,高效的数据传输与管理机制均构成实现局域网内计算机控制功能的核心要素。本文将深入探究 Go 语言中的链表数据结构,剖析其在局域网内计算机控制过程中,如何达成数据的有序存储与高效传输,并通过完整的 Go 语言代码示例展示其应用流程。
198 0