You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++实现Graham Scan凸包算法返回错误路径问题求助

问题定位与修复方案

1. 致命语法错误:Vector2D 加减运算符实现错误

你写的加减法运算符误用了逗号表达式,没有正确构造Vector2D对象:

// 错误写法
Vector2D Vector2D::operator+(const Vector2D& aRHS) const
{
    return (fX + aRHS.fX, fY + aRHS.fY);
}

逗号表达式会先计算左边的fX + aRHS.fX然后丢弃,最终返回仅传入y值的Vector2D对象,所有向量运算完全失效。
修正方案:

Vector2D Vector2D::operator+(const Vector2D& aRHS) const
{
    return Vector2D(fX + aRHS.fX, fY + aRHS.fY);
}
// 减法同理修正
Vector2D Vector2D::operator-(const Vector2D& aRHS) const
{
    return Vector2D(fX - aRHS.fX, fY - aRHS.fY);
}

2. 方向计算逻辑错误

Vector2D::direction()用atan(fY/fX)计算方向存在象限错误,atan的返回值范围只有[-π/2, π/2],无法区分一/三象限、二/四象限的同斜率向量。
修正方案:改用atan2函数,覆盖全象限方向:

double Vector2D::direction() const
{
    return atan2(fY, fX);
}

3. 共线判断逻辑错误

Point2D::isCollinear当前计算的是两个点相对于全局坐标原点的叉乘,不是相对于凸包基准原点的叉乘,共线判断完全失效。
修正方案:基于两个点的相对向量计算叉乘,同时增加浮点精度判断:

bool Point2D::isCollinear(const Point2D& aOther) const
{
    Vector2D v1 = *this - getOrigin();
    Vector2D v2 = aOther - getOrigin();
    return fabs(v1.cross(v2)) < 1e-8;
}

4. 极角排序基准错误

你在buildConvexHull排序前,没有将所有点的Origin设置为找到的最低点(凸包基准点),导致极角排序是基于全局坐标原点而非凸包基准点,排序结果完全错误,这也是p12没有出现在凸包里的核心原因。
修正方案:排序前设置基准原点:

void Point2DSet::buildConvexHull(Point2DSet& aConvexHull)
{
    aConvexHull.clear();
    sort(orderByCoordinates);
    // 新增:将第一个点(y最小的基准点)设置为所有点的Origin
    for (auto& p : fPoints) {
        p.setOrigin(fPoints[0]);
    }
    sort(orderByPolarAngle);
    // 后续逻辑修改
}

5. Graham Scan遍历逻辑错误

当前遍历只弹出一次栈顶元素,正确逻辑是只要栈顶三个点不构成左拐,就要循环弹出栈顶;同时你跳过共线点的逻辑会误删凸包点。
修正方案:

void Point2DSet::buildConvexHull(Point2DSet& aConvexHull)
{
    // 前面排序、设Origin的逻辑省略
    aConvexHull.add(fPoints[0]);
    aConvexHull.add(fPoints[1]);
    for(size_t i = 2; i < size(); i++) 
    {
        // 循环弹出直到构成左拐
        while(aConvexHull.size() >= 2 && aConvexHull.doesNotTurnLeft(fPoints[i]))
        {
            aConvexHull.removeLast();
        }
        aConvexHull.add(fPoints[i]);
    }
    // 可选:添加第一个点闭合凸包,方便输出边
    aConvexHull.add(fPoints[0]);
}

6. 其他细节错误

  • Point2D::operator<只比较y坐标,y相等时应该比较x坐标,确保找到y最小、x最小的基准点:
bool Point2D::operator<(const Point2D& aRHS) const
{
    if (fabs(fPosition.getY() - aRHS.getY()) > 1e-8) {
        return fPosition.getY() < aRHS.getY();
    }
    return fPosition.getX() < aRHS.getX();
}
  • isClockwise函数中无用的val2计算可以删除,减少不必要的性能开销。
代码优化建议
  • 极角排序可以直接用叉乘判断,不需要计算atan2,既避免象限问题又提升性能。
  • 共线点处理可以统一在排序阶段完成,极角相同的点保留距离最远的,遍历阶段不需要单独处理。
  • 可以添加输入校验逻辑,避免点集数量小于3时的边界错误。

内容的提问来源于stack exchange,提问作者Bernard Joshua

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 13:48:03