OVH Cloud OVH Cloud

Structure meilleure que map et lower_bound/upper_bound

6 réponses
Avatar
Fabien LE LEZ
Bonjour,

J'ai une classe qui ressemble à :

struct Machin
{
int rouge;
int vert;
int bleu;
// quelques autres membres...
};

Je voudrais stocker un demi-million d'instances de cette classe dans
un tableau, de telle sorte que, étant donné un
Machin reference
je puisse trouver rapidement tous les élements x du tableau tels que :
reference.rouge * 0.7 <= x.rouge <= reference.rouge * 1.4
&& reference.vert * 0.7 <= x.vert <= reference.vert * 1.4
&& reference.bleu * 0.7 <= x.bleu <= reference.bleu * 1.4


Pour l'instant, je n'ai rien trouvé de mieux que
map <int, map <int, map <int, vector<Machin> > > >
et des lower_bound et upper_bound.

Le point positif : ça marche :-)

Les points négatifs : le code de recherche est un peu tarabiscoté ; de
plus, changer le nombre de paramètres est compliqué -- et impossible
au moment de l'exécution.

Quelqu'un pourrait-il me proposer une structure plus adaptée ?

Merci d'avance...

6 réponses

Avatar
Manuel Zaccaria
"Fabien LE LEZ" a écrit:

Bonjour,



Bonjour

J'ai une classe qui ressemble à :

struct Machin
{
int rouge;
int vert;
int bleu;
// quelques autres membres...
};

Je voudrais stocker un demi-million d'instances de cette classe dans
un tableau, de telle sorte que, étant donné un
Machin reference
je puisse trouver rapidement tous les élements x du tableau tels que :
reference.rouge * 0.7 <= x.rouge <= reference.rouge * 1.4
&& reference.vert * 0.7 <= x.vert <= reference.vert * 1.4
&& reference.bleu * 0.7 <= x.bleu <= reference.bleu * 1.4


Pour l'instant, je n'ai rien trouvé de mieux que
map <int, map <int, map <int, vector<Machin> > > >
et des lower_bound et upper_bound.

Le point positif : ça marche :-)

Les points négatifs : le code de recherche est un peu tarabiscoté ; de
plus, changer le nombre de paramètres est compliqué -- et impossible
au moment de l'exécution.

Quelqu'un pourrait-il me proposer une structure plus adaptée ?


Je me demande si boost::multi_index_container<> ferait l'affaire...

Manuel

Avatar
loufoque

J'ai une classe qui ressemble à :

struct Machin
{
int rouge;
int vert;
int bleu;
// quelques autres membres...
};

Je voudrais stocker un demi-million d'instances de cette classe dans
un tableau, de telle sorte que, étant donné un
Machin reference
je puisse trouver rapidement tous les élements x du tableau tels que :
reference.rouge * 0.7 <= x.rouge <= reference.rouge * 1.4
&& reference.vert * 0.7 <= x.vert <= reference.vert * 1.4
&& reference.bleu * 0.7 <= x.bleu <= reference.bleu * 1.4



Qu'est-ce qui empêche de mettre ces instances dans un std::vector par
exemple puis de parcourir ce conteneur pour trouver les instances voulues ?

Avatar
Loïc Joly
Bonjour,

J'ai une classe qui ressemble à :

struct Machin
{
int rouge;
int vert;
int bleu;
// quelques autres membres...
};

Je voudrais stocker un demi-million d'instances de cette classe dans
un tableau, de telle sorte que, étant donné un
Machin reference
je puisse trouver rapidement tous les élements x du tableau tels que :
reference.rouge * 0.7 <= x.rouge <= reference.rouge * 1.4
&& reference.vert * 0.7 <= x.vert <= reference.vert * 1.4
&& reference.bleu * 0.7 <= x.bleu <= reference.bleu * 1.4


Une idée comme ça, à toi de creuser voir si elle tient debout ;)

Tu peux considérer ces valeurs comme des coordonnées de points dans un
espace à dimension n (ici 3). Il y a des structures comme les Quadtrees
(Q-Tree) ou les R-Tree (et sûrement d'autres encore) qui permettent
alors d'avoir avec des bonnes perfs les points à proximité d'un autre.

--
Loïc

Avatar
Sylvain
Fabien LE LEZ wrote on 17/07/2006 22:07:

Je voudrais stocker un demi-million d'instances de cette classe dans
un tableau, de telle sorte que, étant donné un
Machin reference
je puisse trouver rapidement tous les élements x du tableau tels que :
reference.rouge * 0.7 <= x.rouge <= reference.rouge * 1.4
&& reference.vert * 0.7 <= x.vert <= reference.vert * 1.4
&& reference.bleu * 0.7 <= x.bleu <= reference.bleu * 1.4


tu veux très rapidement trouver le premier et à cout variable, non nul,
trouver le suivant; ou trouver le plus rapidement possible tous les
élements (à itérer sans cout) ?

tu t'autorises quel cout mémoire par Machin stocké ? quel cout max pour
des index dynamiques ?

Sylvain.

Avatar
Sylvain
Fabien LE LEZ wrote on 17/07/2006 22:07:

Je voudrais stocker un demi-million d'instances de cette classe dans
un tableau, de telle sorte que, étant donné un
Machin reference
je puisse trouver rapidement tous les élements x du tableau tels que :
reference.rouge * 0.7 <= x.rouge <= reference.rouge * 1.4
&& reference.vert * 0.7 <= x.vert <= reference.vert * 1.4
&& reference.bleu * 0.7 <= x.bleu <= reference.bleu * 1.4


avec un vector redimensionnable par pas de 100.000 et qSortable, je
génère 500.000 Machin en 156 ms avec r,g,b issu de rand() (donc 0 <= x <
32767)

avec un Machin reference arbitrairement choisi (rand() x 3), j'extrais
21571 références (192685 items après premier critère, 79696 après
second) vérifiant les 3 inégalités en 735 ms sur un P4 2.8 GHz, ça doit
pouvoir aller plus vite avec qlq options d'optim.; c'est trop lent pour
ton usage ?

Sylvain.

Avatar
kanze
Fabien LE LEZ wrote:

J'ai une classe qui ressemble à :

struct Machin
{
int rouge;
int vert;
int bleu;
// quelques autres membres...
};

Je voudrais stocker un demi-million d'instances de cette
classe dans un tableau, de telle sorte que, étant donné un
Machin reference
je puisse trouver rapidement tous les élements x du tableau tels que :
reference.rouge * 0.7 <= x.rouge <= reference.rouge * 1.4
&& reference.vert * 0.7 <= x.vert <= reference.vert * 1.4
&& reference.bleu * 0.7 <= x.bleu <= reference.bleu * 1.4

Pour l'instant, je n'ai rien trouvé de mieux que
map <int, map <int, map <int, vector<Machin> > > >
et des lower_bound et upper_bound.

Le point positif : ça marche :-)

Les points négatifs : le code de recherche est un peu
tarabiscoté ; de plus, changer le nombre de paramètres est
compliqué -- et impossible au moment de l'exécution.


Autre point négatif, peut-être : ça bouffe un maximum de
mémoire:-). Et risque d'avoir une localité assez mauvaise. (Pour
des petits ensembles d'un démi-million d'éléments, je ne crois
pas que ça pose réelement un problème.)

Quelqu'un pourrait-il me proposer une structure plus adaptée ?


Je ne sais pas, mais je crois que je serais parti d'un simple
std::vector< Machin >, maintenu trié selon un critère de tri qui
va bien. (C-à-d une utilisation de std::lower_bound lors de
l'insertion.) Soit, éventuellement, un std::vector< Machin >, et
trois std::vector< Machin* >, trié chacun sur un des couleurs.
(Note bien qu'en tant que structure, il se peut que les quatre
vecteurs ensemble utilise moins de mémoire que ton map.)
Ensuite : c'est facile à trouver des itérateurs de bornes pour
chacune des couleurs, et un petit coup de std::set_intersection
doit faire la reste. (Note bien que pour que set_intersection
soit utilisable, il faut créer des vecteurs intermédiaire trier
sur le même critère. Ce qui est bien si chacun des critères
éliminer la plupart des éléments, mais risque fort de poser un
problème si par exemple 90% des éléments passe un des critères.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34