找到一个圆圈内的网格的所有点,按照规范排序

时间:2012-02-29 17:30:43

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

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

我写了一个有效的实现(是的,我知道,这是非常低效的,但对于我的问题,任何更多的东西都是矫枉过正的)。我是C ++的新手,所以我最大的问题是找到一个能够

的数据结构
  1. 可分类;
  2. 能够在其中一个元素中保存数组,
  3. 而不是算法的实现。我的代码如下。提前谢谢大家!

    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;
    }
    

2 个答案:

答案 0 :(得分:4)

  

如何解决在以圆心为中心的圆内寻找(整数)网格点的问题,结果按照范数排序,如距离中心的距离,在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]&amp;&amp ;;的所有有效点。 y = [0,x]&amp;&amp;圈内的(x,y):

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"));
}

答案 1 :(得分: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);