假设我有一对整数,例如(1,3),(5,6),(7,8),(3,9)那么我想根据它们中的共同元素将这些对组合成唯一的集合即我可以结合(1,3)和(3,9),因为它们之间有3个共同点,所以上面输入的最终输出应该是这样的(1,3,9),(5,6),(7,8) ) 一种方法可能是迭代通过这个数组并基于公共元素组合它并从数组中删除第二对,我认为这是耗时的。 在C / C ++中执行此操作的有效方法是什么?
答案 0 :(得分:3)
这样做的一种有效方法是将其视为图形连接问题。创建一个图形,其中节点是整数对,如果它们对应的对具有公共元素,则在两个节点之间添加无向边。现在,在此图中找到连接的组件,并构造由组中节点对应的对的联合形成的集合。
查找已连接的组件需要O(E)
时间,如果有O(n^2)
对,则可能为n
。将它们全部合并可以使用类似heap
的结构,每次插入需要O(log n)
。因此,运行时为O(E + n log n)
,最多为O(n^2)
。复杂性可能会低很多,具体取决于有多少对具有共同的元素。
答案 1 :(得分:1)
我使用的地图从int
到shared_ptr<list<int>>
,list
覆盖vector
,因为这是splice
的良好用例:< / p>
class Combiner {
std::unordered_map<int, std::shared_ptr<std::list<int>>> map;
public:
void addPair(const std::pair<int, int>& p) {
auto a = map.find(p.first);
auto b = map.find(p.second);
// 4 cases: (1) both found the same list, (2) both found different lists,
// (3) one found a list, (4) neither found a list
if (a != map.end()) {
if (b != map.end()) {
if (a->second == b->second) {
// (1) nothing to do, done
}
else {
// (2) have to combine our lists
a->second->splice(a->second.end(), *(b->second));
b->second = a->second;
}
}
else {
// (3), add p.second to a
a->second->push_back(p.second);
map.insert(std::make_pair(p.second, a->second));
}
}
else {
if (b != map.end()) {
// (3), add p.first to b
b->second->push_back(p.first);
map.insert(std::make_pair(p.first, b->second));
}
else {
// (4), make a new list
auto new_list = std::make_shared<std::list<int>>();
new_list->push_back(p.first);
new_list->push_back(p.second);
map.insert(std::make_pair(p.first, new_list));
map.insert(std::make_pair(p.second, new_list));
}
}
}
答案 2 :(得分:1)
您想要什么类型的容器?他们定了吗?
#include <algorithm>
#include <set>
#include <list>
#include <iostream>
void dump( const std::string & label, const std::list< std::set< int > > & values )
{
std::cout << label << std::endl;
for( auto iter : values )
{
std::cout << "{ ";
for( auto val : iter )
std::cout << val << ", ";
std::cout << "}, ";
}
std::cout << std::endl;
}
void combine( std::list< std::set< int > > & values )
{
for( std::list< std::set< int > >::iterator iter = values.begin(); iter != values.end(); ++iter )
for( std::list< std::set< int > >::iterator niter( iter ); ++niter != values.end(); )
if( std::find_first_of( iter->begin(), iter->end(), niter->begin(), niter->end() ) != iter->end() )
{
iter->insert( niter->begin(), niter->end() );
values.erase( niter );
niter = iter;
}
}
int main( int argc, char ** argv )
{
std::list< std::set< int > > to_process = { { 1, 3 }, { 5, 6 }, { 7, 8 }, { 3, 9 } };
dump( "Before", to_process );
combine( to_process );
dump( "After", to_process );
to_process = { { 1, 3 }, { 5, 6 }, { 7, 8 }, { 3, 9 }, { 9, 13 }, { 8, 11 } };
dump( "Before", to_process );
combine( to_process );
dump( "After", to_process );
to_process = { { 1, 2 }, { 5, 6 }, { 7, 8 }, { 3, 9 }, { 9, 13 }, { 8, 13 } };
dump( "Before", to_process );
combine( to_process );
dump( "After", to_process );
return 0;
}
输出:
Before
{ 1, 3, }, { 5, 6, }, { 7, 8, }, { 3, 9, },
After
{ 1, 3, 9, }, { 5, 6, }, { 7, 8, },
Before
{ 1, 3, }, { 5, 6, }, { 7, 8, }, { 3, 9, }, { 9, 13, }, { 8, 11, },
After
{ 1, 3, 9, 13, }, { 5, 6, }, { 7, 8, 11, },
Before
{ 1, 2, }, { 5, 6, }, { 7, 8, }, { 3, 9, }, { 9, 13, }, { 8, 13, },
After
{ 1, 2, }, { 5, 6, }, { 3, 7, 8, 9, 13, },