C ++ функция для сортировки двумерного массива координат и вычисления ограничивающего прямоугольника - PullRequest
0 голосов
/ 20 июня 2019

У меня есть массив из n двойных массивов размером 2:

double **stored_points_;

Мне нужно написать функцию, которая сортирует эти координаты в порядке возрастания на основе заданной оси (x или y) и хранит ихотсортированные координаты в новом 2d массиве.Мне также нужна функция, которая вычисляет ограничивающую рамку для координат и сохраняет в двух заданных выходных параметрах.

Я уже успешно написал конструктор копирования, геттер, сеттер и т. Д. Я попытался создать своего рода пузырьсортировать, но не могу понять, как заставить его работать с двумерным массивом.

Я ожидаю, что

, если координаты (1,5), (2,2), (1,1), (1,3) результат, когда ось = 0: (1,1), (1,3), (1,5), (2,2) результат, когда ось = 1: (1,1), (2, 2), (1,3), (1,5)

//function definitions from class Points2D{}:

void SortByAxis(size_t axis, double** sorted_points) const;
//axis: 0 means sort by x-axis, 1 means sort by y-axis

void CalcBoundingBox(double lower_left[2], double upper_right[2])     const;

//some members of class Points2D{}:

public:
  static const size_t x = 0;
  static const size_t y = 0;
private:  0;
  double **stored_points_;

1 Ответ

2 голосов
/ 20 июня 2019

Как уже указывалось immibis :

Обратите внимание, что сортировка двумерного массива аналогична сортировке обычного одномерного массива, в котором сортируемые элементы являются массивами.

Я хотел бы добавить, что OP, мы надеемся, знает, что двумерный массив (массив массивов) - это не то, что было открыто OP.

double **stored_points - указатель на double* и может представлять массив double*. Это не совместимый тип, например, double points[][2]. (В SO много вопросов и ответов по этому поводу:
SO: Почему мы не можем использовать двойной указатель для представления двумерных массивов?
на самом деле помечен , но также относится к .)

Стандартная библиотека уже предоставляет готовый std::sort() для сортировки различных контейнеров (включая массивы), которые можно использовать в большинстве распространенных случаев & ndash; один из OP включительно:

Сортирует элементы в диапазоне [первый, последний) в порядке возрастания. Порядок равных элементов не гарантируется для сохранения.

Предоставленная сложность std::sort() - это O (N & middot; log (N)) & rarr; намного лучше, чем сложность Bubble sort (OP считается использованным), который равен O (N²).

Доступно несколько вкусов. В случае OP требуется специальный компаратор, так как значение по возрастанию может быть изменено по запросу.

Следовательно,

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp )

выбрано.

Параметры

первый, последний - диапазон сортируемых элементов

comp - объект функции сравнения (т. Е. Объект, который удовлетворяет требованиям Compare), который возвращает значение true, если первый аргумент меньше (т. Е. Упорядочен раньше) второго.

Подпись функции сравнения должна быть эквивалентна следующей:

bool cmp(const Type1 &a, const Type2 &b);

Хотя подпись не обязательно должна иметь const &, функция не должна изменять переданные ей объекты и должна иметь возможность принимать все значения типа (возможно, const) Type1 и Type2 независимо от категории значения (таким образом, Type1 & не допускается и не является Type1, если только для Type1 перемещение не эквивалентно копии (начиная с C ++ 11)). Типы Type1 и Type2 должны быть такими, чтобы объект типа RandomIt мог быть разыменован, а затем неявно преобразован в оба из них.

Для double **stored_points, в first stored_points может быть передано, в last stored_points + n. Таким образом, n - это размер массива. Это не упоминается в открытом коде OP, но это абсолютно необходимое значение. Указатель может представлять массив любой длины. Я знаю только два способа получить длину массива из указателя: либо предоставить его отдельно, либо использовать определенное значение в качестве конечного маркера (как это делается в строках C с '\0').

Для компаратора должна быть передана функция (или функтор) с соответствующей сигнатурой. В данном конкретном случае это

bool(double* const &, double* const &)

но (еще лучше)

bool(double*, double*)

тоже подойдет.

Это может быть функция, функтор (то есть класс с operator()) или лямбда (которая напоминает одну из первых). Я решил использовать лямбду (чтобы мой код был минимальным):

    [](double *pt1, double *pt2) {
      return pt1[0] != pt2[0] // if first elements unequal
        ? pt1[0] < pt2[0] // return whether first first < second first
        : pt1[1] < pt2[1]; // else whether first second < second second
    }

Это обеспечивает меньший оператор сравнения первого подэлемента, учитывая второй подэлемент, только если первый равен. Этот меньший компаратор определяет Order , который необходим в std::sort() для определения значения по возрастанию.

Чтобы изменить порядок (для сортировки с ведущими координатами y), используется просто другая лямбда:

    [](double *pt1, double *pt2) {
      return pt1[1] != pt2[1] // if second elements unequal
        ? pt1[1] < pt2[1] // return whether first second < second second
        : pt1[0] < pt2[0]; // else whether first first < second first

На самом деле выглядит довольно схожим образом только индексы поменялись местами.


Полный пример:

#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>

// a print function (usable in output streams)
std::string print(double **data, size_t n)
{
  std::ostringstream out;
  const char *sep = "";
  for (size_t i = 0; i < n; ++i) {
    out << sep << '(' << data[i][0] << ", " << data[i][1] << ')';
    sep = ", ";
  }
  return out.str();
}

int main()
{
  // sample data of OP
  double points[][2] = {
    { 1, 5 }, { 2, 2 }, { 1, 1 }, { 1, 3 }
  };
  const size_t n = sizeof points / sizeof *points; // let compiler determine
  // resemble input data of OP
  double *stored_points[n];
  for (size_t i = 0; i < n; ++i) stored_points[i] = points[i];
  // show input data
  std::cout
    << "Input data:\n"
    << "  " << print(stored_points, n) << '\n';
  // sort in ascending order with leading x:
  std::sort(stored_points, stored_points + n,
    [](double *pt1, double *pt2) {
      return pt1[0] != pt2[0] // if first elements unequal
        ? pt1[0] < pt2[0] // return whether first first < second first
        : pt1[1] < pt2[1]; // else whether first second < second second
    });
  // show result
  std::cout
    << "Data sorted by leading x:\n"
    << "  " << print(stored_points, n) << '\n';
  // sort in ascending order with leading y:
  std::sort(stored_points, stored_points + n,
    [](double *pt1, double *pt2) {
      return pt1[1] != pt2[1] // if second elements unequal
        ? pt1[1] < pt2[1] // return whether first second < second second
        : pt1[0] < pt2[0]; // else whether first first < second first
    });
  // show result
  std::cout
    << "Data sorted by leading y:\n"
    << "  " << print(stored_points, n) << '\n';
  // done
  return 0;
}

Выход:

Input data:
  (1, 5), (2, 2), (1, 1), (1, 3)
Data sorted by leading x:
  (1, 1), (1, 3), (1, 5), (2, 2)
Data sorted by leading y:
  (1, 1), (2, 2), (1, 3), (1, 5)

Демонстрация в реальном времени на coliru

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...