利用并查集(Disjoint Set)解决一道算法题

一:并查集数据结构

计算机科学中,并查集是一种树型的数据结构,其保持着用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。有一个联合-查找算法(union-find algorithm)定义了两个操作用于此数据结构:

  • Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
  • Union:将两个子集合并成同一个集合。

因为它支持这两种操作,一个不相交集也常被称为联合-查找数据结构(union-find data structure)或合并-查找集合(merge-find set)。其他的重要方法,MakeSet,用于建立单元素集合。有了这些方法,许多经典的划分问题可以被解决。

二:并查集结构基本操作的实现

#define MAX 100

int father[MAX];  //用于记录对应节点的父节点
int rank[MAX];   //用于两个集合合并时进行比较

int make_set(int nums)
{
	for (int i=0;i<nums;i++)
	{
		father[i]=i; //默认父节点为自己的编号
	}

	return 0;
}
//查找某个元素所在集合的代表
//在一棵树中,可以认为是查找该节点所在树的根节点
int find_set(int x)
{
	if (x!=father[x])
	{
		father[x]=find_set(father[x]);//路径压缩,更精确的应该加上rank[]的修改
	}

	return father[x];
}

//如果两个元素在同一个集合就返回,否则依据rank进行集合的合并
void union_set(int x,int y)
{
	x=find_set(x);
	y=find_set(y);
	if (x==y)
		return ;
	if (rank[x]>rank[y])
	{
		father[y]=x;
	}
	else
	{
		if (rank[x]==rank[y])
		{
			rank[y]++;
		}
		father[x]=y;
	}
}
三:算法问题的描述

If there are different pairs of characters, each pair of the characters means the two matching characters are the same. Print out all the identical characters. 

For example: 

if you have pairs: 

A-B 
C-D 
E-F 
G-H 
A-D 
F-G 

you should print out: 
{A, B, C, D} are the same characters. 
{E, F, G, H} are the same characters. 

四:利用并查集的解决方案

针对问题,建立叫Pair的结构,用于记录每一个pair中的两个字符,以及一个ID用于区别不同的Pair。把每一个pair当做并查集中的基本元素来进行前面进行的基本操作,为方便使用,建立一个map<Pair,int>,用于记录每个Pair与父节点之间的对应关系。代码实现如下:

#include <iostream>
#include <map>
using namespace std;

#define MAX 100

typedef struct  
{
	char first;
	char second;
	int ID; //唯一区分每个Pair
}Pair;

map<Pair,int> father_map;
int rank[MAX];


int make_set(Pair& temp_pair)
{
	father_map[temp_pair]=temp_pair.ID;
	rank[temp_pair.ID]=0;
}

int find_set(Pair& l_pair)
{
   int father;
   map<Pair,int>::const_iterator iter=father_map.find(l_pair);
   if (iter!=father_map.end())
   {
	   father=iter->second;
   }
   if (father!=l_pair->ID)
   {
	   father=find_set(iter->first);
   }

   father_map[l_pair]=father;

   return father;
}

void union_set(Pair lpair,Pair rpair)
{
	int lfather=find_set(lpair);
	int rfather=find_set(rpair);
	if (lfather==rfather)
	{
		return ;
	}
	if (rank[lfather]>rank[rfather])
	{
		father_map[rpair]=lfather;
	}
	else
	{
		if (rank[lfather]==rank[rfather])
		{
			rank[rfather]++;
		}
		father_map[lpair]=rfather;
	}
}

五:参考资料

http://zh.wikipedia.org/wiki/%E5%B9%B6%E6%9F%A5%E9%9B%86

http://www.cnblogs.com/cherish_yimi/archive/2009/10/11/1580839.html




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值