编辑:如果你想要走额外的步骤,你应该考虑Disjoint-set 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)
摊销。
为什么'A.is_associated(5,10)'真的吗?你能否更详细地解释该关联逻辑? – 2012-02-06 19:23:09
序列'5-> 3-> 6-> 8> 10'。 – 2012-02-06 19:25:57
似乎因为没有一个回答者能够理解这个问题:/ – 2012-02-06 19:26:19