2010-11-13 5 views
2

Je souhaite créer un ensemble de points triés en fonction des coordonnées x ou y.C++, comparateur, pointeur vers la fonction

typedef std::set <Point2D, sorter> Points; 

Pour le type de «Point», je voudrais utiliser un comparateur différent. La première trie points selon les coordonnées x, la seconde selon les coordonnées Y:

typedef std::set <Point2D, sortPointsByX()> Points; 
typedef std::set <Point2D, sortPointsByy()> Points; 

class sortPoints2DByX 
{ 
    public: 

      bool operator() (const Point2D &p1, const Point2D &p2); 

}; 

class sortPoints2DByY 
{ 
    public: 

      bool operator() (const Point2D &p1, const Point2D &p2); 

}; 

est-il possible de créer un pointeur sur la classe constructeur sortPoints2DByX/sortPoints2DByY en Déclaration de points

typedef std::set <Point2D, pointer_to_somparator_class> Points; 

et par la nécessité d'utiliser l'un d'entre eux?

Je dois avoir un type de données peut être trié de deux façons.

Si cette idée est fausse, existe-t-il une solution plus appropriée?

je dois calculer la médiane des coordonnées x et y ...

Merci pour votre aide ...

+0

est le problème que vous avez besoin de changer la façon dont un ensemble est trié, ou est le problème que vous devez être en mesure de passer la faire le tour sans avoir les choses que vous lui passez pour avoir deux méthodes différentes pour les deux types de jeu différents? – Omnifarious

+0

J'ai deux solutions qui sont toutes deux basées sur le fait que ':: std :: set' prendra un comparateur comme argument constructeur. Cela ne vous permettra pas de réorganiser un ensemble à la volée, mais il vous permettra d'utiliser le même type pour conserver deux ordres différents dans deux objets différents. @ André Caron a aussi une solution basée sur l'argument du constructeur ':: std :: set'. – Omnifarious

Répondre

-1

J'ai deux solutions, qui ont tous deux été testés:

Tout d'abord, code commun à la fois:

class Point2D { 
public: 
    Point2D(int x, int y) : x_(x), y_(y) { } 

    int getX() const { return x_; } 
    int getY() const { return y_; } 

private: 
    int x_, y_; 
}; 

Et la fonction principale ...

int main(int argc, char *argv[]) 
{ 
    Points s1(compareByX); 
    Points s2(compareByY); 
    const int size = 1750; 

    for (int x = -size; x <= size; ++x) { 
     for (int y = -size; y <= size; ++y) { 
     Point2D p(x, y); 
     s1.insert(p); 
     s2.insert(p); 
     } 
    } 
    return 0; 
} 

Maintenant, pour la solution 1:

#include <tr1/functional> 
#include <set> 

typedef ::std::tr1::function<bool (const Point2D &, const Point2D &)> comparefunc_t; 
typedef ::std::set <Point2D, comparefunc_t> Points; 

bool compareByX(const Point2D &a, const Point2D &b) 
{ 
    return (a.getX() != b.getX()) ? 
     (a.getX() < b.getX()) : (a.getY() < b.getY()); 
} 

bool compareByY(const Point2D &a, const Point2D &b) 
{ 
    return (a.getY() != b.getY()) ? 
     (a.getY() < b.getY()) : (a.getX() < b.getX()); 
} 

Et bien plus la solution 2:

class Point2DComparator { 
public: 
    virtual bool operator()(const Point2D &a, const Point2D &b) const = 0; 

protected: 
    const Point2DComparator &operator =(const Point2DComparator &b) { 
     return *this; 
    } 
    Point2DComparator(const Point2DComparator &b) { } 
    Point2DComparator() { } 
}; 

class Point2DComparatorEnvelope : public Point2DComparator { 
public: 
    Point2DComparatorEnvelope(const Point2DComparator &letter) 
     : letter_(letter) 
    { 
    } 

    virtual bool operator()(const Point2D &a, const Point2D &b) const { 
     return letter_(a, b); 
    } 

private: 
    const Point2DComparator &letter_; 
}; 

class XComparator : public Point2DComparator { 
public: 
    virtual bool operator() (const Point2D &a, const Point2D &b) const { 
     return (a.getX() != b.getX()) ? 
       (a.getX() < b.getX()) : (a.getY() < b.getY()); 
    } 
}; 

class YComparator : public Point2DComparator { 
public: 
    virtual bool operator() (const Point2D &a, const Point2D &b) const { 
     return (a.getY() != b.getY()) ? 
       (a.getY() < b.getY()) : (a.getX() < b.getX()); 
    } 
}; 

typedef ::std::set<Point2D, Point2DComparatorEnvelope> Points; 
XComparator compareByX; 
YComparator compareByY; 

Ils semblent pratiquement (sans jeu de mots) identique performance. La seconde est beaucoup plus complexe, mais si vous regardez les internaux de ::std::tr1::function vous verrez que c'est extrêmement poilu. La seconde est principalement utile à des fins de démonstration. À mon humble avis, la norme est brisée pour exiger l'enveloppe stupide/lettre hack pour l'ensemble du travail.

+0

Je veux construire KD-tree et j'ai besoin de calculer rapidement et à plusieurs reprises médiane ... – Ian

+0

Cela ne fonctionnera pas. Parce que 'std :: set <>' fera une copie d'un 'Point2DSorter', vos instances vont être découpées et l'opérateur de comparaison approprié ne sera pas appelé. –

+0

@Ian: si votre vraie question est de savoir comment implémenter un arbre KD, il n'y a pas de conteneur standard qui fournit directement cette fonctionnalité. –

2

Est-il possible de créer un pointeur vers les classes constructPoints2DByX/sortPoints2DByY dans la déclaration des points?

Non, vous ne pouvez pas prendre l'adresse d'un constructeur de classe.

Je dois avoir un type de données qui peut être trié de deux façons.

Vous pouvez vous déplacer en utilisant des pointeurs vers des fonctions.Exemple la mise en œuvre:

#include <algorithm> 
#include <set> 
#include <iostream> 

    // Your implementation may differ. 
struct Point 
{ 
    int x; int y; 
    Point(int x_, int y_) 
     : x(x_), y(y_) {} 
}; 

    // For display purposes. 
void print(const Point& point) 
{ 
    std::cout << '(' << point.x 
     << ',' << point.y << ')' << std::endl; 
} 

bool OrderByX (const Point& lhs, const Point& rhs) 
{ 
    return (lhs.x < rhs.x); 
} 

bool OrderByY (const Point& lhs, const Point& rhs) 
{ 
    return (lhs.y < rhs.y); 
} 

    // Type of comparison operator. 
typedef bool(*Comparator) 
    (const Point&lhs,const Point&rhs); 

    // Set used to store points in sorted order. 
typedef std::set<Point, Comparator> Points; 

int main (int, char **) 
{ 
     // Each set ordered with it's own criteria. 
    Points by_x(&OrderByX); 
    Points by_y(&OrderByY); 

     // Insert each point in both sets. 
    by_x.insert(Point(1,2)); by_y.insert(Point(1,2)); 
    by_x.insert(Point(3,1)); by_y.insert(Point(3,1)); 
    by_x.insert(Point(4,3)); by_y.insert(Point(4,3)); 
    by_x.insert(Point(2,4)); by_y.insert(Point(2,4)); 

     // Show that 1st set is in proper order. 
    std::cout << "Sorted by X:" << std::endl; 
    std::for_each(by_x.begin(), by_x.end(), &print); 
    std::cout << std::endl; 

     // Show that 2nd set is in proper order. 
    std::cout << "Sorted by Y:" << std::endl; 
    std::for_each(by_y.begin(), by_y.end(), &print); 
    std::cout << std::endl; 
} 

Il génère la sortie suivante:

Sorted by X: 
(1,2) 
(2,4) 
(3,1) 
(4,3) 

Sorted by Y: 
(3,1) 
(1,2) 
(4,3) 
(2,4) 
Questions connexes