Найти все точки сетки внутри круга, упорядоченные по норме - PullRequest
2 голосов
/ 29 февраля 2012

Как бы вы решили проблему нахождения точек (целочисленной) сетки внутри круга с центром в начале оси, с результатами, упорядоченными по норме, как на расстоянии от центра, в 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;
}

Ответы [ 2 ]

4 голосов
/ 29 февраля 2012

Как бы вы решили проблему нахождения точек (целочисленной) сетки внутри круга с центром в начале оси, с результатами, упорядоченными по норме, как на расстоянии от центра, в 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, радиусу] && y = [0, x] && (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"));
}
2 голосов
/ 29 февраля 2012

Всегда стоит добавить класс точек для такой геометрической задачи, так как обычно вам нужно решить более одного. Но я не думаю, что это хорошая идея перегрузить оператор '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);
...