关于集合合并的算法

neusoft_jifm 2014-02-12 09:30:33
有多个集合,每个集合中有或多或少个数;
凡事有过交集的集合都要合并到一起。
输入
{1,3,4} {2,3,5} {6,7} {2,8} {3,9}
输出
{1,2,3,4,5,8,9} {6,7}

...全文
1071 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
spawn888 2014-08-15
  • 打赏
  • 举报
回复
最慢的方法,用蛮力去挨个比较,只要两个集合存在相同元素,就合并,否则继续与下一个集合比较,内外层循环结束后,就得到了若干个独立的集合。
kosora曹 2014-08-11
  • 打赏
  • 举报
回复
引用 7 楼 zhoujinjun0858 的回复:
好久都没有写过代码了,编程水平直线下降,编程也不严谨了,我这个代码可以复制后直接运行,只不过预编译头文件我没有放上来!感谢2楼的提醒,还请多多指教!
大哥,你这程序,放到哪一个OJ上都会TLE;此类题除了并查集,没有别的办法. http://baike.baidu.com/view/521705.htm?fr=aladdin
王者荣耀zhou 2014-06-28
  • 打赏
  • 举报
回复
好久都没有写过代码了,编程水平直线下降,编程也不严谨了,我这个代码可以复制后直接运行,只不过预编译头文件我没有放上来!感谢2楼的提醒,还请多多指教!
王者荣耀zhou 2014-06-28
  • 打赏
  • 举报
回复
我已经写好了一个程序,用的就是2楼的思路,不知道哪里可以上传附件啊!
#pragma once

#include <vector>
#include <map>
#include <queue>

using namespace std;

class GraphicNode;

class Graphic
{
public:
	Graphic(void);
	
	~Graphic(void);

	// 添加图结点(true:新增加结点成功  false:已经有结点)
	bool AddNode(int & node_val);

	// 在两个结点之间建立联通
	bool AddRelation(int & node1 , int & node2);

	// 从根结点开始遍历相互联通的所有结点
	bool VisitUnionNodes(int & root_val);
 
	// 打印与root连通的结点集合
	void PrintCollection(void);
protected:
	int num_of_nodes;  //图结点数目

	//图结点集合,以结点的值作为key,图中无重复结点
typedef map<int,GraphicNode *> GRAPHIC_NODES;
	GRAPHIC_NODES  nodes;

	//用于输出连通结点的队列
typedef queue<int> UNION_COLLECTION;
	UNION_COLLECTION   union_collection;

};
#include "StdAfx.h"
#include "Graphic.h"
#include "GraphicNode.h"
#include <iostream>


Graphic::Graphic(void)
{
}


Graphic::~Graphic(void)
{
   GRAPHIC_NODES::iterator it = nodes.begin();
   GRAPHIC_NODES::iterator it_end = nodes.end();
   while( it != it_end )
   {
	   delete it->second; //删除图结点
	   it ++;
   }
   nodes.clear();
}


// 添加图结点
bool Graphic::AddNode(int & node_val)
{
	if ( this->nodes.find(node_val) != nodes.end())   return false;  //已经存在该结点

	GraphicNode *pNode = new GraphicNode();
	pNode->SetNodeVal( node_val );
	this->nodes.insert(pair<int,GraphicNode *>(node_val,pNode));
	
	return false;
}


// 在两个结点之间建立联通
bool Graphic::AddRelation(int & node1 , int & node2)
{
	GRAPHIC_NODES::iterator it1 = nodes.find(node1);
	GRAPHIC_NODES::iterator it2 = nodes.find(node2);

	if ( it1 == nodes.end() || it2 == nodes.end() ) return false;  //结点不存在,无法在两个结点之间建立连通
	
	it1->second->PointToNeighbor(node2);  //node1 ---> node2
	it2->second->PointToNeighbor(node1);  //node2 ---> node1
	
	return true;
}


// 从根结点开始遍历相互联通的所有结点
bool Graphic::VisitUnionNodes(int & root_val)
{
	GRAPHIC_NODES::iterator it = nodes.find(root_val);
	GraphicNode *pNode = it->second;
	if ( !pNode->bVisited )
	{
		pNode->bVisited = true; //已经遍历过
		union_collection.push(pNode->GetDataVal());

		GraphicNode::PNEIGHBOR_NODES pNei = pNode->GetNeighborList();

		GraphicNode::NEIGHBOR_NODES::iterator it = pNei->begin();
		GraphicNode::NEIGHBOR_NODES::iterator it_end = pNei->end();
		
		while ( it != it_end)
		{
			VisitUnionNodes(*it);
			it ++;
		}
	}
	return false;
}



// 打印与root连通的结点集合
void Graphic::PrintCollection(void)
{
	if (union_collection.empty())  return ;
	
	while ( !union_collection.empty())
	{
		cout<<union_collection.front()<<"     ";
		union_collection.pop();
	}
	cout<<endl<<"-------------------"<<endl;
}
#pragma once

#include <vector>

using namespace std;


class GraphicNode
{
public:

	typedef vector<int> NEIGHBOR_NODES;
	typedef NEIGHBOR_NODES* PNEIGHBOR_NODES;	
	
	GraphicNode(void);

	~GraphicNode(void);

	// 设置结点数值
	void SetNodeVal(int & data);	

	// 获取结点的值
	int GetDataVal(void) const;

	// 使得该结点指向邻居节点
	bool PointToNeighbor(int & nei_node);

	// 获取邻居结点列表
	GraphicNode::PNEIGHBOR_NODES GetNeighborList(void) ;

	//是否被访问过,用于遍历,初始化为false
	bool bVisited;
protected:
	int data; //节点数值

    NEIGHBOR_NODES  neighbor;  //邻居结点:以结点数值为key

};

#include "StdAfx.h"
#include "GraphicNode.h"


GraphicNode::GraphicNode(void)
{
	this->bVisited = false;  //初始结点没有被访问过
}


GraphicNode::~GraphicNode(void)
{
}

// 设置结点数值
void GraphicNode::SetNodeVal(int & data)
{
	this->data = data;
}


// 使得该结点指向邻居节点
bool GraphicNode::PointToNeighbor(int & nei_node)
{
    NEIGHBOR_NODES::iterator it = this->neighbor.begin();
    NEIGHBOR_NODES::iterator it_end = this->neighbor.end();

	while ( it != it_end && *it != nei_node )    it ++;

	if ( it == it_end )  //没有找到,添加邻居
	{
		this->neighbor.push_back(nei_node);
		return true;
	}
	else  // ( *it == nei_node ) //找到邻居结点
	{
		return false;
	}

}


// 获取结点的值
int GraphicNode::GetDataVal(void) const
{
	return this->data;
}


// 获取邻居结点列表
GraphicNode::PNEIGHBOR_NODES GraphicNode::GetNeighborList(void) 
{
	return (&this->neighbor);
}
// CollectionUnion.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "Graphic.h"

using namespace std;


//---集合组---
typedef vector<int>  COLLECTION;
typedef vector<COLLECTION> COLLECTIONS;

//#define MAX_COLLECTIONS_SIZE  500
COLLECTIONS   collections;  

//---------------------------------------------------------------------------
// 初始化若干个集合
void InitCollections()
{
	int nCollectionCount = 0;  //集合个数
	int coll_elem_count = 0;   //每个集合元素个数
	int elem;


	cout<<"请输入集合个数:"<<endl;
	cin>>nCollectionCount;
	collections.reserve(nCollectionCount);  //予保留的容量,但是元素个数为0

	for ( int i = 0 ;i < nCollectionCount; i++ )
	{
		COLLECTION Col;
		collections.push_back(Col); //size增加
		cout<<"请输入第"<<i<<"组集合元素个数:"<<endl;
		cin>>coll_elem_count;
		cout<<"请输入元素值:"<<endl;

		for ( int j = 0; j < coll_elem_count; j++  )
		{
			cin>>elem;
			collections[i].push_back(elem);
		}
	}
}

// 用集合元素建立图
void InitGraphic(Graphic * pGraphic)
{
	COLLECTIONS::iterator cols_it = collections.begin();
	COLLECTIONS::iterator cols_end = collections.end();

	COLLECTION::iterator  col_it ,col_end;

	for (  ;cols_it != cols_end; cols_it ++ )
	{
		col_it = cols_it->begin();
		col_end = cols_it->end();

		for ( ; col_it != col_end; col_it ++)
		{
			pGraphic->AddNode(*col_it); 
		}
	}
}

// 在有交集的集合各元素之间建立连通
void UnionAllNodes(Graphic * pGrap)
{
	COLLECTIONS::iterator cols_it = collections.begin();
	COLLECTIONS::iterator cols_end = collections.end();
	COLLECTION::iterator col_root, col_it,col_end;

	while ( cols_it != cols_end )
	{
		 col_root = cols_it->begin();
		 col_end =  cols_it->end();
		 col_it = col_root;
		 col_it ++;
		 while ( col_it != col_end )
		 {
			 pGrap->AddRelation(*col_root,*col_it);
			 col_it ++;
		 }

		 cols_it ++;
	}

}

// 输出所有连通的结点,即输出有交集的集合
void GetCollections(Graphic *pGrap)
{
	COLLECTIONS::iterator cols_it = collections.begin();
	COLLECTIONS::iterator cols_end = collections.end();
	COLLECTION::iterator  col_it;
	cout<<"有交集的集合:"<<endl;
	while( cols_it != cols_end)
	{
		col_it = cols_it->begin();
		pGrap->VisitUnionNodes(*col_it);
		pGrap->PrintCollection();

		cols_it ++;
	}

}

//
//==============================================================================
//

int _tmain(int argc, _TCHAR* argv[])
{

	Graphic * collecions_grp = new Graphic();

	InitCollections();

	InitGraphic(collecions_grp);

	UnionAllNodes(collecions_grp);
	
	GetCollections(collecions_grp);

	delete collecions_grp;

	return 0;
}

wkwdeveloper 2014-05-08
  • 打赏
  • 举报
回复
引用 1 楼 FancyMouse 的回复:
并查集。每个输入的集合{1,3,4}分解成两个Merge操作:Merge(1,3), Merge(3,4)。然后再把root值相同的放在一起输出就行。
1L讲的思路能否讲清楚一点,看不懂, 能否有人解答下
MBSHENG 2014-03-12
  • 打赏
  • 举报
回复
根据1L的想法试了一下

void unionSets(int root1, int root2){
s[root1] = root2;
}

int find(int x){
if( s[x] == x){
return x;
}

return find(s[x]);
}

void Init(){
for(int i = 0; i < 10; i++)
s[i] = i;
}

bool isContinue( int i, vector<int> &vec){
for( size_t j = 0; j < vec.size(); j++){
if( i == vec[j])
return true;
}

return false;
}

void Print(){

vector<int> already;
for( int i = 1; i < 10 ; i++){
if( isContinue(i, already)) continue;
printf( "%d,", i);
for( int j = i + 1; j < 10; j++){
if( find(i) == find(j)){
printf( "%d,", j);
already.push_back(j);
}
}
printf("\n");
}

getchar();

}

void Union( vector<vector<int>> &unions){

Init();

for( vector<vector<int>>::iterator itr = unions.begin(); itr != unions.end(); itr++){
vector<int> arr = *itr;
int pre = -1;
for( vector<int>::iterator itr2 = arr.begin(); itr2 != arr.end(); itr2++){
if( arr.size() > 1){
if( itr2 == arr.begin() ){
pre = *itr2;
continue;
}else{
int a = find(pre);
int b = find(*itr2);

unionSets(a, b);
}

pre = *itr2;
}else{
s[*itr2] = *itr2;
}
}
}

Print();
}


cnmhx 2014-03-11
  • 打赏
  • 举报
回复
对每个元素遍历搜索,具有同样元素的合并为一个子集。
熊熊大叔 2014-02-14
  • 打赏
  • 举报
回复
每个数字作为图上的一个节点,处于相同集合中的节点之间有边相连。这个问题就是求图中的连通集。
FancyMouse 2014-02-13
  • 打赏
  • 举报
回复
并查集。每个输入的集合{1,3,4}分解成两个Merge操作:Merge(1,3), Merge(3,4)。然后再把root值相同的放在一起输出就行。

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧