连通域查找使用并行方法,需要对图片接触行列进行标签合并,连通域标签合并过程可以形式化为一个二分图。
二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
寻找二分图的连通子图,用于解决传导等价类问题。
图1 中有两个连通子图
C++代码:
//输入为二部图的边集合,无重复
int findEqualSetBinGraph(
std::hash_multimap<int,int> &equelHashL,
std::hash_multimap<int,int> &equelHashR,
std::vector<int> &vetexL,
std::vector<int> &vetexR,
std::vector< std::pair<std::vector<int>,std::vector<int> > > &equelSet,
bool bStack )
{
//使用堆栈,删除遍历过的边
if ( equelHashL.size() >0 )
{
std::stack<std::pair< int, int > > edgeEs;//使用边堆栈
std::stack< int > pSL,pSR;//左边堆栈
std::vector< int > pVL,pVR;//左右等价集合
for ( int i=0; i< vetexL.size();++i)
{//从左侧开始//遍历过的顶点边的个数为0
pVL.resize(0);
pVR.resize(0);
int VL = vetexL[i];
pSL.push(vetexL[i]);
pVL.push_back(VL);
while ( !pSL.empty() )
{
VL = pSL.top();
auto ptr =equelHashR.find(VL);
int C = equelHashR.count(VL);
if ( C> 0)
{
auto ptr1 =equelHashR.lower_bound(VL);
auto ptr2 =equelHashR.upper_bound(VL);
for (int i=0;i<C;++i)
{
pSR.push(ptr1->second);
pVR.push_back(ptr1->second);
++ptr1;
}
pSL.pop();
//去除掉相连的边
equelHashR.erase( VL );
//遍历对方的边
while ( !pSR.empty() )
{
int VR = pSR.top();
auto ptr =equelHashL.find(VR);
int C = equelHashL.count(VR);
if ( C > 1 )
{
auto ptr1 =equelHashL.lower_bound(VR);
auto ptr2 =equelHashL.upper_bound(VR);
for (int i=0;i<C;++i)//绕过第一个,必须要顺序排列才能使用
{
if ( ptr1->second != VL )
{
pSL.push(ptr1->second);
pVL.push_back( ptr1->second );
//删除右边元素
auto ptrR =equelHashR.lower_bound( ptr1->second );
for ( int i =0; i< equelHashR.count( ptr1->second ); ++i )
{
if ( ptrR->second == VR)
{
equelHashR.erase(ptrR);
break;
}
else
{
++ptrR;
}
}
}
++ptr1;
}
pSR.pop();
equelHashL.erase( VR );
}
else
{
//删除右边元素
int VR = pSR.top();
auto ptrR = equelHashL.lower_bound( VR );
for ( int i =0; i< equelHashL.count( VR ); ++i )
{
if ( ptrR->second == VL)
{
equelHashL.erase(ptrR);
break;
}
else
{
++ptrR;
}
}
pSR.pop();
}
}
}
else
{
pSL.pop();
}
}
if ( pVL.size()>0 && pVR.size()>0 )
{
equelSet.push_back( std::make_pair( pVL,pVR ) );
}
}
}
return 1;
}
//输入为二部图的边集合,有重复
int findEqualSetBinGraph(
std::vector< std::pair<int,int> > &edgeSet,
std::vector< std::pair<std::vector<int>,std::vector<int> > > &equelSet,
bool bStack )
{
//4.2筛选集合//划分等价类//使用查找划分等价类
std::vector< std::pair<int,int> > equelLabelL,equelLabelR,equelLabelMin,equelLabelMinMirro;
equelLabelL.reserve(edgeSet.size() );
//等价集合
std::vector< std::pair<std::vector<int>,std::vector<int> > > equelSetL,equelSetR;//,equelSet,;
std::map<int,int> equelMapL,equelMapR;//使用多值哈希//设置重复集合//用于最后合并连通域
std::hash_multimap<int,int> equelHashL,equelHashR;
std::vector<int> vetexL,vetexR;//顶点集合
if ( edgeSet.size()>0 )
{
std::qsort(&edgeSet[0],edgeSet.size(),sizeof(edgeSet[0]) ,cvWish::Operater::cmpPairIntFirst);
//使用基数排序//一次合并完成
{
int idxS =0;
int idxE =0;
int vL;
vL = edgeSet[0].first;
for ( idxE ; idxE< edgeSet.size(); ++idxE )
{
if ( idxE == 0 )
{
continue;
}
if ( vL == edgeSet[idxE].first ){
}
else
{
vL = edgeSet[idxE].first;
std::qsort(&edgeSet[idxS],idxE-idxS,sizeof(edgeSet[0]) ,cvWish::Operater::cmpPairIntSecond );
idxS = idxE;
}
}
std::qsort(&edgeSet[idxS],idxE-idxS,sizeof(edgeSet[0]) ,cvWish::Operater::cmpPairIntSecond );
}
equelLabelMin.reserve( edgeSet.size() );//equelLabelMin.reserve( equelLabelR.size() );
{
int vL,vR;
vL = edgeSet.begin()->first;
vR = edgeSet.begin()->second;
equelLabelMin.push_back( std::make_pair(vL,vR) );
for ( auto ptr = edgeSet.begin(); ptr!= edgeSet.end(); ++ptr)
{
if (ptr == edgeSet.begin())
{//跳过第一个
continue;
}
if ( vL == ptr->first && vR == ptr->second)
{
}
else
{
vL = ptr->first;
vR = ptr->second;
equelLabelMin.push_back( std::make_pair(vL,vR) );
}
//vL = ptr->first;
//vR = ptr->second;
}
}
for ( auto ptr = equelLabelMin.begin(); ptr!= equelLabelMin.end(); ++ptr)
{
equelHashR.insert( *ptr );
equelLabelMinMirro.push_back( std::make_pair( ptr->second,ptr->first ) );
}
std::qsort(&equelLabelMinMirro[0],equelLabelMinMirro.size(),sizeof(equelLabelMinMirro[0]) ,cvWish::Operater::cmpPairIntFirst );
{
int idxS =0;
int idxE =0;
int vL = equelLabelMinMirro[0].first;
for ( idxE ; idxE< equelLabelMinMirro.size(); ++idxE )
{
if ( idxE == 0 )
{
continue;
}
if ( vL == equelLabelMinMirro[idxE].first ){
}
else
{
vL = equelLabelMinMirro[idxE].first;
std::qsort(&equelLabelMinMirro[idxS],idxE-idxS,sizeof(equelLabelMinMirro[0]) ,cvWish::Operater::cmpPairIntSecond );
idxS = idxE;
}
}
std::qsort(&equelLabelMinMirro[idxS],idxE-idxS,sizeof(equelLabelMinMirro[0]) ,cvWish::Operater::cmpPairIntSecond );
}
for ( auto ptr = equelLabelMinMirro.begin(); ptr!= equelLabelMinMirro.end(); ++ptr)
{
equelHashL.insert(*ptr );//多值hash和多值map都不能剔除重复条目,不应该啊!
}
bool bStack = true;
//4.3 找出顶点集合//暂时不需要,根据所有的边找出顶点
vetexL.reserve(equelLabelMin.size());
{
int vL,vR;
vL = equelLabelMin.begin()->first;
vetexL.push_back(vL);
for (auto ptr = equelLabelMin.begin(); ptr!= equelLabelMin.end();++ptr)
{
if (ptr == equelLabelMin.begin())
{//跳过第一个
continue;
}
if ( vL == ptr->first ){
}
else
{
vL = ptr->first;
vetexL.push_back(vL);
}
}
}
vetexR.reserve( equelLabelMinMirro.size() );
{
int vL,vR;
vR = equelLabelMinMirro.begin()->first;
vetexR.push_back(vR);
for (auto ptr = equelLabelMinMirro.begin(); ptr!= equelLabelMinMirro.end();++ptr)
{
if ( ptr == equelLabelMinMirro.begin())
{//跳过第一个
continue;
}
if ( vR == ptr->first ){
}
else
{
vR = ptr->first;
vetexR.push_back(vR);
}
}
}
}
//使用堆栈法寻找连通子图
//边集合: equelLabelMin,equelLabelMinMirros,但使用equelHashL equelHashR 顶点集合: vetexL,vetexR
findEqualSetBinGraph(equelHashL,equelHashR,vetexL,vetexR,equelSet,bStack );
return 1;
}