并查集类的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& ...
随机推荐
- 史上最全面的FRM与CFA的区别对比分析,适合新人看
简单地自我介绍:本人于纽约完成了研究生阶段的学习后,在华尔街混迹了几年的时间,已获取FRM证书,正在积极准备CFA. 上海财经大学FRM培训中心前言导读 经常看到CFA持证人平均年收入为$XXX之类的 ...
- Codeforces 364A - Matrix
原题地址:http://codeforces.com/problemset/problem/364/A 题目大意: 给定一个数字a(0 ≤ a ≤ 109)和一个数列s(每个数都是一位,长度不超过40 ...
- MySQL优化器 limit影响的case
测试的用例中,因为limit的大小不同,而产生了完全不同的执行计划: 1. 测试case: create table t1 ( f1 ) not null, f2 ) not null, f3 ) n ...
- bzoj3156
斜率优化dp,比较裸 注意int64的运算 ..] of int64; i,n,h,t:longint; x,y,z:int64; function g(j,k:int64):doub ...
- 让Codeigniter控制器支持多级目录
<?php if (!defined('BASEPATH')) { exit ('No direct script access allowed');} class MY_Router exte ...
- 【转】Android动态改变对 onCreateDialog话框值 -- 不错不错!!!
原文网址:http://www.111cn.net/sj/android/46484.htm 使用方法是这样的,Activity.showDialog()激发Activity.onCreateDial ...
- sql null值
SQL Server 提供 SET CONCAT_NULL_YIELDS_NULL { ON | OFF } 来控制 null 与其它字符串连接的行为. 当 SET CONCAT_NULL_YIELD ...
- HDU 5319 Painter
题意:红色从左上向右下涂,蓝色从右上向左下涂,既涂红色又涂蓝色就变成绿色,问最少涂几下能变成给的图. 解法:模拟一下就好了,注意细节. 代码: #include<stdio.h> #inc ...
- JMX学习笔记(二)-Notification
Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...
- Cordova CrossWalk
http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/cordova-2-cordovabarcodescanner/ 军训结束后,同学们 ...