并查集类的c++封装,比較union_find algorithm四种实现方法之间的性能区别
问题描写叙述:
在计算机科学中,并查集是一种树型的数据结构,其保持着用于处理一些不相交集合(Disjoint
Sets)的合并及查询问题。有一个联合-查找算法(union-find algorithm)定义了两个操作用于此数据结构:
Find:确定元素属于哪一个子集。它能够被用来确定两个元素是否属于同一子集;
Union:将两个子集合并成同一个集合;
实现并查集的关键是实现union-find algorithm, 本文依据经常使用的四种算法,实现了这个类,详细算法实现请參看维基百科;
制造測试数据集,測试几种方法之间性能的指标;
程序代码:
#ifndef _DISJOINT_SET_H_
#define _DISJOINT_SET_H_ #include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <time.h>
#include <math.h> #include "windows.h" enum DISJOINTWAY
{
COMMON_WAY,
COMPREE_WAY,
WEIGHT_WAY,
WEIGHT_COMPRESS_WAY
}; /*
* encapsulate the class of disjoint set
*
*/ #define MAXDISJOINTSET 0xffffff
class DisjointSet
{
public:
DisjointSet( int maxSize = MAXDISJOINTSET ):m_item(0), m_size(maxSize)
{
m_item = new int[maxSize];
for( int i = 0; i < m_size; i++ )
{
m_item[i] = i;
} m_path = new int[maxSize];
memset( m_path, 1, sizeof(int)*maxSize );
} ~DisjointSet()
{
Clear();
} /*
* find interface
*
*/
int Find( DISJOINTWAY way, int input )
{
assert( input < m_size );
switch( way )
{
case COMMON_WAY:
return ImplFindFirst( input );
case COMPREE_WAY:
return ImplFindSecond( input );
case WEIGHT_WAY:
return ImplFindWeight( input );
case WEIGHT_COMPRESS_WAY:
return ImplFindWeightCompree( input );
default:
return -1;
}
} /*
* make union
*
*/
void Union( DISJOINTWAY way, int first, int second )
{
assert( first < m_size && second < m_size );
switch( way )
{
case COMMON_WAY:
ImplUnionFirst( first, second );
break;
case COMPREE_WAY:
ImplUnionSecond( first, second );
break;
case WEIGHT_WAY:
ImplUnionWeighted( first, second );
break;
case WEIGHT_COMPRESS_WAY:
ImplUnionCompree( first, second );
break;
default:
break;
} } /*
*
*
*/
void Clear()
{
delete [] m_item;
m_item = 0; delete [] m_path;
m_path = 0; m_size = 0;
} protected: int ImplFindFirst( int input )
{
assert( input < m_size );
return m_item[input];
} int ImplFindSecond( int input )
{
int i = input;
for( ; i != m_item[i]; i = m_item[i] ); return i;
} int ImplFindWeight( int input )
{
int i = input;
for( ; i != m_item[i]; i = m_item[i] ); return i; } int ImplFindWeightCompree( int input )
{
int i = input;
for( ; i != m_item[i]; i = m_item[i] )
m_item[i] = m_item[m_item[i]]; return i;
} /*
*
*
*/
void ImplUnionFirst( int first, int second )
{
int x = m_item[first];
int y = m_item[second]; if( x != y )
{
m_item[first] = y;
} for( int i = 0; i < m_size; i++ )
{
if( x == m_item[i] )
m_item[i] = y;
}
} /*
*
*
*/
void ImplUnionSecond( int& first, int& second )
{
if( first != second )
{
m_item[first] = second;
}
} /*
*
*
*/
void ImplUnionWeighted( int first, int second )
{
if( first != second )
{
if( m_path[first] < m_path[second] )
{
m_item[first] = second;
m_path[second] += m_path[first];
}
else
{
m_item[second] = first;
m_path[first] += m_path[second];
}
}
} /*
*
*
*/
void ImplUnionCompree( int first, int second )
{
if( first != second )
{
if( m_path[first] < m_path[second] )
{
m_item[first] = second;
m_path[second] += m_path[first];
}
else
{
m_item[second] = first;
m_path[first] += m_path[second];
}
} } protected: int* m_item;
int m_size; int* m_path; }; void TestDisjointSetSimple()
{
DisjointSet djoint;
int i = djoint.Find( COMMON_WAY, 1 );
int j = djoint.Find( COMMON_WAY, 3 );
if( i != j )
djoint.Union( COMMON_WAY, 1, 3 ); i = djoint.Find( COMMON_WAY, 2 );
j = djoint.Find( COMMON_WAY, 5 );
if( i != j )
djoint.Union( COMMON_WAY, i, j ); i = djoint.Find( COMMON_WAY, 2 );
j = djoint.Find( COMMON_WAY, 6 );
if( i != j )
djoint.Union( COMMON_WAY, i, j ); i = djoint.Find( COMMON_WAY, 6 );
j = djoint.Find( COMMON_WAY, 7 );
if( i != j )
djoint.Union( COMMON_WAY, i, j ); assert( djoint.Find( COMMON_WAY, 2 ) == djoint.Find( COMMON_WAY, 7 ) ); i = djoint.Find( COMMON_WAY, 1 );
j = djoint.Find( COMMON_WAY, 7 );
if( i != j )
djoint.Union( COMMON_WAY, i, j ); assert( djoint.Find( COMMON_WAY, 3 ) == djoint.Find( COMMON_WAY, 7 ) );
} void TestDisjointSetComplex( DISJOINTWAY way, const char* str )
{ unsigned long start = GetTickCount();
DisjointSet djoint; const int len = 1000000;
const int base = 60000;
int halfLen = len / 2;
srand( time(NULL) );
for( int i = 0; i < len; i++ )
{
int first = rand() % base;
int second = rand() % base;
if( i > halfLen )
{
first += base;
second += base;
} if( first != second )
{
first = djoint.Find( way, first );
second = djoint.Find( way, second );
if( first != second )
djoint.Union( way, first, second ); assert( djoint.Find( way, first ) == djoint.Find( way, second ) );
}
} unsigned long interval = GetTickCount() - start;
printf(" %s way consume time is %d \n", str, interval ); } void TestSuiteDisjointSet()
{
TestDisjointSetSimple(); const char* str[] = {"common", "compress", "weight", "weight compress"};
for( int i = WEIGHT_COMPRESS_WAY; i >= 0; i--)
{
TestDisjointSetComplex((DISJOINTWAY)i, str[i] );
} } #endif
compile and run in visual studio 2005
以下图片是几种方法执行时间之比較,最直白方法的时间到如今还没输出,所以就没有显示:
并查集类的c++封装,比較union_find algorithm四种实现方法之间的性能区别的更多相关文章
- 百度地图和高德地图坐标系的互相转换 四种Sandcastle方法生成c#.net帮助类帮助文档 文档API生成神器SandCastle使用心得 ASP.NET Core
百度地图和高德地图坐标系的互相转换 GPS.谷歌.百度.高德坐标相互转换 一.在进行地图开发过程中,我们一般能接触到以下三种类型的地图坐标系: 1.WGS-84原始坐标系,一般用国际GPS纪录仪记 ...
- get,post,put,delete四种基础方法对应增删改查
PUT,DELETE,POST,GET四种基础方法对应增删改查 1.GET请求会向数据库发索取数据的请求,从而来获取信息,该请求就像数据库的select操作一样,只是用来查询一下数据,不会修改.增加数 ...
- 四种Sandcastle方法生成c#.net帮助类帮助文档
方法一 前端时间在网上收集和自己平时工作总结整理了<干货,比较全面的c#.net公共帮助类>,整理完成上传github之后我又想,既然是帮助类,总得有个帮助文档于是乎想到了Sandcast ...
- 类与接口(二)java的四种内部类详解
引言 内部类,嵌套在另一个类的里面,所以也称为 嵌套类; 内部类分为以下四种: 静态内部类 成员内部类 局部内部类 匿名内部类 一.静态内部类 静态内部类: 一般也称"静态嵌套类" ...
- RBAC类在ThinkPHP中的四种使用方法
第一类:放在登陆控制器的登陆操作中 1.RBAC::authenticate(); 用于在用户表中查找表单提交的用户名的数据,实质上就是一条用户表查寻语句,=====> return M(mod ...
- 关于android studio中使用class.forname()方法动态获取类实例报NO CLASS FOUND异常的几种处理方法
最近在做一个项目的时候需要用到反射来回调子类的方法,但是在反射过程中总是在class.forname()方法抛出NO CLASS FOUND异常,经过几部检查,问题解决,在此总结一下引起该问题的原因 ...
- Hashtable类中的四种遍历方法对比
要遍历一个Hashtable,api中提供了如下几个方法可供我们遍历: keys() - returns an Enumeration of the keys of this Hashtable ke ...
- poj1456(贪心+并查集)
题目链接: http://poj.org/problem?id=1456 题意: 有n个商品, 已知每个商品的价格和销售截止日期, 每销售一件商品需要花费一天, 即一天只能销售一件商品, 问最多能买多 ...
- poj 2236 并查集
并查集水题 #include<cstdio> #include<iostream> #include<algorithm> #include<cstring& ...
随机推荐
- poj 2195 Going Home(最小费用最大流)
题目:http://poj.org/problem?id=2195 有若干个人和若干个房子在一个给定网格中,每人走一个都要一定花费,每个房子只能容纳一人,现要求让所有人进入房子,且总花费最小. 构造一 ...
- BMap介绍
API引用路径: <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&am ...
- Webapp meta标签解决移动缩放的问题
webapp开发初期,会碰到在pc端开发好的页面在移动端显示过大的问题,这里需要在html head中加入meta标签来控制缩放 <meta name=" viewport" ...
- Cookie帮助类
using System; using System.Collections.Generic; using System.Text; using System.Web; namespace AIMSC ...
- 分布式数据库中间件TDDL、Amoeba、Cobar、MyCAT架构比较分
比较了业界流行的MySQL分布式数据库中间件,关于每个产品的介绍,网上的资料比较多,本文只是对几款产品的架构进行比较,从中可以看出中间件发展和演进路线 框架比较 TDDL Amoeba Cobar M ...
- 如何使用spring中的Log4jConfigListener--删除
使用spring中的Log4jConfigListener有如如下好处: 1. 动态的改变记录级别和策略,不需要重启Web应用,如<Effective Enterprise Java> ...
- 初次接触Object对象变量
Object 变量存储为 32 位(4 个字节)的地址形式,其为对象的引用.利用 Set 语句,声明为 Object 的变量可以赋值为任何对象的引用. 第一次注意到还有个数据类型,帮助文件里只有上面这 ...
- POJ 2001 字典树(入门题)
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #i ...
- Java内存结构、类的初始化、及对象构造过程
概述 网上关于该题目的文章已经很多,我觉得把它们几个关联起来讲可能更好理解一下.与其它语言一样,它在执行我们写的程序前要先分配内存空间,以便于存放代码.数据:程序的执行过程其实依然是代码的执行及数据的 ...
- Python第一个入门程序
#!usr/bin/env python3 #在UNIX上,当某程序在控制台中被引用时,该文件的头两个字节先被读入.如果这两个字节是ASCII字符 #!, #shell就会认为该文件将要由解释器执行, ...