Редактировать: Если вы хотите сделать дополнительный шаг, вам следует подумать об эффективной реализации Несвязанное множество Union-Find .
К сожалению, единственный разумный способ, который я вижу, это сделать std::map
более std::sets
- вам нужно каждый раз при вставке проверять, находятся ли два элемента в разных подмножествах - если это так, вы объединяете их.
Таким образом, внешний набор хранит все элементы и указывает их на наборы, к которым они принадлежат.
Теперь, если вы добавите новую ассоциацию:
- проверка, к каким наборам относятся A и B
- если ни один из них не принадлежит ни одному из наборов, создайте новый набор и сопоставьте оба значения этому набору (конец)
- если один принадлежит набору, а другой нет, поместите другой в первый набор и отобразите его там (конец)
- если оба принадлежат разным наборам, объедините наборы и соответственно обновите сопоставления элементов.
Теперь функция is_associated очень быстрая - просто проверьте, принадлежат ли два элемента одному и тому же набору.
На английском:
typedef std::map< int, std::set< int >& > assoc_set; // note that you need to
// store the sets somewhere else, maybe in another set
Что-то вроде этого:
class assoc_set
{
typedef std::set< int > int_set;
typedef std::set< int_set > int_set_set;
typedef std::map< int, int_set_set::iterator > set_map;
public:
void associate( int a, int b )
{
set_set_map::iterator ia = iss.find( a );
set_set_map::iterator ib = iss.find( b );
if ( ia == set_set_map::end() )
{
if ( ib == set_set_map::end() )
{
// create new
int_set ab;
ab.insert(a);
ab.insert(b);
int_set_set::iterator r = iss.insert( ab ).second;
smap[a] = r;
smap[b] = r;
}
else
{
// add to a
smap[a] = ib;
ib->insert( a );
}
}
else
{
if ( ib == set_set_map::end() )
{
// add to b
smap[b] = ia;
ia->insert( b );
}
else
{
// merge
ia->insert( ib->begin(), ib->end() );
// this could be done better
for ( int_set::iterator i = it->begin(); i != it->end(); ++i )
{
smap[*i] = ia;
}
}
}
}
bool is_associated( int a, int b )
{
set_set_map::iterator ia = iss.find( a );
set_set_map::iterator ib = iss.find( b );
return ia != set_set_map::end() && ia = ib;
}
private:
int_set_set iss;
set_map smap;
}
Будут ошибки и ошибки, у меня есть только блокнот (и я все равно потратил слишком много времени на это).
Добавление составляет O(n)
(но может быть уменьшено до O(log(n))
путем использования дополнительного уровня косвенности (и избавления от глупого цикла карты). Запрос - O(log(n))
.
Используя unordered_set/unordered_map
, вы можете уменьшить оба значения до O(1)
.