0

I have an array of n double arrays of size 2:

double **stored_points_;

I need to write a function that sorts these coordinates in ascending order based on a given axis (x or y) and store these sorted coordinates in a new 2d array. I also need a function that calculates a bounding box for the coordinates and stores in the two given output parameters.

I have already successfully written copy constructor, getter, setter, etc. I have tried doing a kind of bubble sort but cannot figure out how to make it work with a 2d array.

What I expect is

if coordinates are (1,5), (2,2), (1,1), (1,3) result when axis = 0: (1,1), (1,3), (1,5), (2,2) result when axis = 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_;
Zari Case
  • 17
  • 5
  • Notice that sorting your 2D array, is the same as sorting a normal 1D array where the items you're sorting happen to be arrays. – user253751 Jun 20 '19 at 01:02
  • Your sorting declaration is incorrect, it should be something like this: struct Point { int x; int y;}; Struct Point *Coordinates; void SortByAxis(size_t axis, Point* sorted_points) ; – Charlie Jun 20 '19 at 06:08

1 Answers1

3

As already pointed out by immibis:

Notice that sorting your 2D array, is the same as sorting a normal 1D array where the items you're sorting happen to be arrays.

I would like to add that OP is hopefully aware that a 2D array (array of arrays) is not what was exposed by OP.

double **stored_points is a pointer to double* and may represent an array of double*. This is not a compatible type to e.g. double points[][2]. (There are numerous Q/As in SO concerning this:
SO: Why can't we use double pointer to represent two dimensional arrays?
is actually tagged with but applies to as well.)

The standard library already provides a ready std::sort() to sort a variety of containers (including arrays) which can be used in most common cases – the one of OP inclusive:

Sorts the elements in the range [first, last) in ascending order. The order of equal elements is not guaranteed to be preserved.

The granted complexity of std::sort() is O(N·log(N)) → much better than the complexity of Bubble sort (OP considered to use) which is O(N²).

There are multiple flavors available. For OPs case, a custom comparator is needed as the meaning of ascending shall be changable on request.

Hence,

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

is chosen.

Parameters

first, last - the range of elements to sort

comp - comparison function object (i.e. an object that satisfies the requirements of Compare) which returns ​true if the first argument is less than (i.e. is ordered before) the second.

The signature of the comparison function should be equivalent to the following:

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

While the signature does not need to have const &, the function must not modify the objects passed to it and must be able to accept all values of type (possibly const) Type1 and Type2 regardless of value category (thus, Type1 & is not allowed, nor is Type1 unless for Type1 a move is equivalent to a copy (since C++11)). The types Type1 and Type2 must be such that an object of type RandomIt can be dereferenced and then implicitly converted to both of them. ​

For double **stored_points, in first stored_points may be passed, in last stored_points + n. Thereby, n is the size of the array. It's not mentioned in OPs exposed code but it's an absolutely necessary value. A pointer can represent an array of any length. I know only two ways to get the length of an array from a pointer: either provide it separately or use a specific value as end marker (like done in C strings with '\0').

For the comparator, a function (or functor) with matching signature has to be passed. In this specific case, it is

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

but (even better)

bool(double*, double*)

will do as well.

This could be a function, a functor (i.e. a class with operator()), or a lambda (which resembles one of the former). I decided to use a lambda (to keep my code minimal):

    [](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
    }

This provides a less operator comparing first sub-element, considering second sub-element only if first is equal. This less comparator defines an Order which is needed in std::sort() to define the meaning of ascending.

To change the order (for sorting with leading y coordinates), just another lambda is used:

    [](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

Looks actually quite similar – just the indices have been swapped.


The complete example:

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

Output:

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)

Live Demo on coliru

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56