【问题标题】:Find all points of a grid within a circle, ordered by norm查找圆内网格的所有点,按范数排序
【发布时间】:2012-03-19 05:12:00
【问题描述】:

您将如何解决在以轴的原点为中心的圆内找到(整数)网格的点的问题,结果按范数排序,如在 C++ 中与中心的距离?

我编写了一个有效的实现(是的,我知道,它的效率极低,但对于我的问题,任何更多的东西都将是矫枉过正的)。我对 C++ 非常陌生,所以我最大的问题是找到一个能够支持

的数据结构
  1. 可排序;
  2. 能够将数组保存在其中一个元素中,

而不是算法的实现。我的代码如下。提前谢谢大家!

typedef std::pair<int, int[2]> norm_vec2d;

bool norm_vec2d_cmp (norm_vec2d a, norm_vec2d b)
{
    bool bo;
    bo = (a.first < b.first ? true: false);
    return bo;
}

int energy_to_momenta_2D (int energy, std::list<norm_vec2d> *momenta)
{
    int i, j, norm, n=0;
    int energy_root = (int) std::sqrt(energy);

    norm_vec2d temp;

    for (i=-energy_root; i<=energy_root; i++)
    {
        for (j =-energy_root; j<=energy_root; j++)
        {
            norm = i*i + j*j;
            if (norm <= energy)
            {
                temp.first = norm;
                temp.second[0] = i;
                temp.second[1] = j;
                (*momenta).push_back (temp);
                n++;
            }
        }
    }
    (*momenta).sort(norm_vec2d_cmp);
    return n;
}

【问题讨论】:

  • 所有 STL 序列容器 (cplusplus.com/reference/stl) 都是可排序的,因为它们是可迭代的。您可以在其中大多数上使用大多数 std(排序)算法。您始终可以创建一个嵌套容器类型(如vector&lt; list&lt;int&gt; &gt;vector&lt; vector&lt;int&gt; &gt;)满足您的其他需求..
  • 如果你不希望我们帮助算法,那为什么要标记它“算法”?
  • 是否必须在对的后半部分有一个数组?为什么不将 x 坐标存储在 pair::first 中,将 y 坐标存储在 pair::second 中?现在您将norm 存储在第一个属性中,但您实际上并不需要存储它,因为您可以随时从 x 和 y 重构它。
  • 对不起,我并不是说我不希望对算法有任何帮助,只是这不是我的首要任务:我总是欢迎更智能的解决方案,尤其是考虑到我的解决方案有多不聪明。关于我为什么存储规范,是因为这样我就可以将参数准备好进行排序。

标签: c++ algorithm data-structures discrete-space


【解决方案1】:

在 C++ 中,您将如何解决在以轴原点为中心的圆内找到(整数)网格点的问题,结果按范数排序,如与中心的距离?

我不会使用std::pair 来保存积分。我会创建自己的更具描述性的类型。

struct Point {
  int x;
  int y;
  int square() const { return x*x + y*y; }
  Point(int x = 0, int y = 0)
    : x(x), y(y) {}
  bool operator<(const Point& pt) const {
    if( square() < pt.square() )
      return true;
    if( pt.square() < square() )
      return false;
    if( x < pt.x )
      return true;
    if( pt.x < x)
      return false;
    return y < pt.y;
  }
  friend std::ostream& operator<<(std::ostream& os, const Point& pt) {
    return os << "(" << pt.x << "," << pt.y << ")";
  }
};

这个数据结构(可能)与两个整数大小完全相同,它的可比性小,它是可分配的,而且很容易打印。

算法遍历所有满足 x=[0,radius] && y=[0,x] && (x,y) inside circle 的有效点:

std::set<Point>
GetListOfPointsInsideCircle(double radius = 1) {
  std::set<Point> result;

  // Only examine bottom half of quadrant 1, then
  // apply symmetry 8 ways
  for(Point pt(0,0); pt.x <= radius; pt.x++, pt.y = 0) {
    for(; pt.y <= pt.x && pt.square()<=radius*radius; pt.y++) {
      result.insert(pt);
      result.insert(Point(-pt.x, pt.y));
      result.insert(Point(pt.x, -pt.y));
      result.insert(Point(-pt.x, -pt.y));
      result.insert(Point(pt.y, pt.x));
      result.insert(Point(-pt.y, pt.x));
      result.insert(Point(pt.y, -pt.x));
      result.insert(Point(-pt.y, -pt.x));
    }
  }
  return result;
}

我选择std::set 来保存数据有两个原因:

  • 它是按顺序存储的,所以我不用std::sort它,而且
  • 它拒绝重复,所以我不必担心反射相同的点

最后,使用这个算法非常简单:

int main () {
  std::set<Point> vp = GetListOfPointsInsideCircle(2);
  std::copy(vp.begin(), vp.end(),
    std::ostream_iterator<Point>(std::cout, "\n"));
}

【讨论】:

  • @japs - 错了。它包括圆上的 一些 点,不包括其他点。等我修好它。
  • @japs - 已修复。它严格列出了圆圈内的点。如果您想要在圆内或圆上点,请参阅评论。要对其进行测试,请使用半径 5 运行并确认 (3,4)(5,0) 要么都包括在内,要么都排除在外。
  • 实际上,对于我的实际情况,我也需要这些点(这些点对我来说是与量子系统中给定能量兼容的所有动量)。感谢您的帮助!
  • @japs - 修改为包含圆上的点。为算法添加了一些优化。
【解决方案2】:

为这样的几何问题添加一个点类总是值得的,因为通常你要解决的问题不止一个。但我认为重载“less”运算符以满足遇到的第一个需求并不是一个好主意。因为:

  • 指定您排序的比较器将使您清楚地知道您想要在那里的顺序。
  • 指定比较器可以轻松更改它,而不会影响您的通用点类。
  • 到原点的距离不是一个错误的顺序,但对于网格来说,使用行和列可能会更好(先按 x 排序,然后按 y 排序)。
  • 此类比较器速度较慢,因此会减慢您甚至不关心规范的任何其他点集。

无论如何,这是一个使用特定比较器并尝试优化一点的简单解决方案:

struct v2i{
    int x,y;
    v2i(int px, int py) : x(px), y(py) {}
    int norm() const {return x*x+y*y;}
};

bool r_comp(const v2i& a, const v2i& b)
    { return a.norm() < b.norm(); }

std::vector<v2i> result;
for(int x = -r; x <= r; ++x) {
    int my = r*r - x*x;
    for(int y = 0; y*y <= my; ++y) {
        result.push_back(v2i(x,y));
        if(y > 0)
            result.push_back(v2i(x,-y));
    }
}

std::sort(result.begin(), result.end(), r_comp);

【讨论】:

  • +1 最好将比较函数传递给std::sort 而不是实现operator&lt;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-30
  • 2015-10-17
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多