co jest dobrym sposobem, aby zaznaczyć element losowy z mapy? C++. Rozumiem, że mapy nie mają iteratorów z dostępem swobodnym. Klucz jest długi, a mapa słabo zaludniona.Losowy element mapie
Odpowiedz
map<...> MyMap;
iterator item = MyMap.begin();
std::advance(item, random_0_to_n(MyMap.size()));
nie próbowałem tego jeszcze, ale jeśli to działa to wygląda idealnie. Spróbuję, kiedy wrócę do domu. co #includes to wymaga? – Deathbob
#include i dołącz
... i upewnić się, że Twój randomusingto_n() jest zawsze
Podoba mi się odpowiedź Jamesa, jeśli mapa jest mała lub jeśli nie trzeba często wybierać losowej wartości. Jeśli jest duży i robisz to wystarczająco często, aby prędkość była ważna, możesz zachować oddzielny wektor kluczowych wartości, aby wybrać losową wartość.
map<...> MyMap;
vector<...> MyVecOfKeys; // <-- add keys to this when added to the map.
map<...>::key_type key = MyVecOfKeys[ random_0_to_n(MyVecOfKeys.size()) ];
map<...>::data_type value = MyMap[ key ];
Oczywiście, jeśli mapa jest naprawdę duża, możesz nie być w stanie przechowywać kopii wszystkich kluczy w tym stylu. Jeśli możesz sobie na to pozwolić, choć masz przewagę wyszukiwania w logarytmicznym czasie.
Mapa nie jest zbyt duża, więc jestem zainteresowany robiąc to w łatwy sposób, ale może stać się duży. Może wtedy warto dostosować nieco klasę mapy, aby umożliwić mi wybieranie losowego klucza w ten sposób bez przechowywania zbędnego wektora. Czy jest już jakiś sposób na zrobienie tego? – Deathbob
Nie sądzę, że istnieje dobry sposób na uzyskanie dostępu do kluczy mapy bez uciekania się do przechodzenia przez mapę w czasie liniowym, ze względu na fakt, że jest ona przechowywana jako drzewo. Czy na pewno mapa jest najlepszą strukturą danych do swoich celów? –
Myślę, że możemy trochę przyspieszyć, zobacz moją odpowiedź. – Constantin
Może należy rozważyć Boost.MultiIndex, choć pamiętać, że jest to trochę zbyt ciężki ważony.
Może sporządzić losowy klucz, a następnie użyć lower_bound aby znaleźć najbliższy klucz rzeczywiście zawarty.
Jeśli klucze są równomiernie rozmieszczone, może to być dobry pomysł. Jeśli nie, możesz skończyć, zdobywając jeden klucz częściej niż inni. –
To jest rzeczywiście sposób na pobranie próbki z [empirycznej dystrybucji] próbki (http://en.wikipedia.org/wiki/Empirical_measure). –
Oto przypadek, gdy elementy mapy muszą być dostępne w kolejności losowej.
- Skopiuj mapę do wektora.
- wektor Shuffle.
W pseudo-kod (Jest ściśle odzwierciedla następujące C++ realizacji):
import random
import time
# populate map by some stuff for testing
m = dict((i*i, i) for i in range(3))
# copy map to vector
v = m.items()
# seed PRNG
# NOTE: this part is present only to reflect C++
r = random.Random(time.clock())
# shuffle vector
random.shuffle(v, r.random)
# print randomized map elements
for e in v:
print "%s:%s" % e,
print
w C++:
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/foreach.hpp>
#include <boost/random.hpp>
int main()
{
using namespace std;
using namespace boost;
using namespace boost::posix_time;
// populate map by some stuff for testing
typedef map<long long, int> Map;
Map m;
for (int i = 0; i < 3; ++i)
m[i * i] = i;
// copy map to vector
#ifndef OPERATE_ON_KEY
typedef vector<pair<Map::key_type, Map::mapped_type> > Vector;
Vector v(m.begin(), m.end());
#else
typedef vector<Map::key_type> Vector;
Vector v;
v.reserve(m.size());
BOOST_FOREACH(Map::value_type p, m)
v.push_back(p.first);
#endif // OPERATE_ON_KEY
// make PRNG
ptime now(microsec_clock::local_time());
ptime midnight(now.date());
time_duration td = now - midnight;
mt19937 gen(td.ticks()); // seed the generator with raw number of ticks
random_number_generator<mt19937,
Vector::iterator::difference_type> rng(gen);
// shuffle vector
// rng(n) must return a uniformly distributed integer in the range [0, n)
random_shuffle(v.begin(), v.end(), rng);
// print randomized map elements
BOOST_FOREACH(Vector::value_type e, v)
#ifndef OPERATE_ON_KEY
cout << e.first << ":" << e.second << " ";
#else
cout << e << " ";
#endif // OPERATE_ON_KEY
cout << endl;
}
Kontynuując ryan_s tematem preconstructed map i szybkiego losowego odnośnika: zamiast wektor możemy użyć równoległej mapy iteratorów, co powinno przyspieszyć losowe wyszukiwanie.
map<K, V> const original;
...
// construct index-keyed lookup map
map<unsigned, map<K, V>::const_iterator> fast_random_lookup;
map<K, V>::const_iterator it = original.begin(), itEnd = original.end();
for (unsigned i = 0; it != itEnd; ++it, ++i) {
fast_random_lookup[i] = it;
}
// lookup random value
V v = *fast_random_lookup[random_0_to_n(original.size())];
Jeśli mapa jest statyczna, a następnie zamiast mapy, użyj wektor do przechowywania par klucz/wartość, aby klucz, wyszukiwania binarnego zajrzeć do wartości log (n) oraz indeks wektor aby uzyskać losowe pary w stałym czasie. Możesz zawęzić wyszukiwanie wektorowe/binarne, aby wyglądało jak mapa z funkcją dostępu losowego.
Czy ktoś próbował tego? https://github.com/mabdelazim/Random-Access-Map „C++ klasa szablon dla dostępie swobodnym mapie. To jest jak std :: map, ale można uzyskać dostęp do elementów losowych przez indeks z my_map.key składni (i) i my_map.data (I)”
Dlaczego trzeba to zrobić? Korzystanie z mapy wynika, chcesz szybko odnośnika na podstawie klucza, losowe wyszukiwanie będzie O (N) ... –