最近在工作中遇到个比较棘手的算法问题,抽象起来其实就类似于交换机的广播风暴的成环检测算法的实现,因为个人有过在新华三集团任职高级固网工程师的经历,所以这个算法设计与实现的任务就落在了我的头上,由于核心代码涉及公司机密,所以我就抽象出来个数学模型来和大家进行交流。
算法的核心是图的遍历,我需要将图的原型虚拟化出来,,进行深度优先遍历,然后入栈出栈保存图中所有环上的结点然后打印出来,以便给配置网络的人以警示,下面是我从业务里抽象出来的源码,可以在vc6.0上运行,每个Node代表一个交换机的端口,enging字段表示网络中交换机的编号,pin表示端口号,InOut表示数据输入或者输出,0代表输入,1代表输出。每个graph代表有向边,有起始结点和结束结点,表示数据从哪个交换机的哪个端口进入或输出到另一个端口的连接。比如最后打印的结果:
nodevector<0>.startengine:1
nodevector<0>.startpin:0
nodevector<0>.startinout:0
nodevector<0>.endengine:1
nodevector<0>.endpin:0
nodevector<0>.endinout:1
表示数据从交换机1的0号端口输入,从交换机1的0号端口输出,大家可能有点奇怪,这不是一个端口吗,为啥要用两个点表示,这是因为一个点没有办法表示输入输出,所以必须一个点虚拟成两个点,然后加上两条有向边(其实就是无向边),所以我这个问题最后演变成了解决虚拟出来的有向图里有个别无向边的成环检测问题,对于无向边需要做特殊处理,下面是代码,有兴趣可以在vc6.0上编译并自行研究,要是我写的不够详细,对算法不了解的同学可以在评论区写出你的疑问,很快进行解答。
// circletest.cpp : Defines the entry point for the console application.
//
#include "StdAfx.h"
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <string>
using namespace std;
enum InOut
{
in,
out,
};
typedef struct node
{
int pin;
string engine;
InOut inout;
}Node;
typedef struct graph
{
Node start;
Node end;
}Graph;
bool isEqual(Node a,Node b)//判断两个node是否相等
{
bool flag = false;
if(a.engine == b.engine && a.inout == b.inout && a.pin == b.pin)
{
flag = true;
}
return flag;
}
bool isInvector(Node n, vector<Node> *vn)//判断node n 是否在vector里面
{
bool flag = false;
for(int i = 0; i < (*vn).size(); i++)
{
if(isEqual(n, (*vn)[i]))
{
flag = true;
}
}
return flag;
}
bool isEqualGraph(Graph a,Graph b)//判断两个Graph是否相等
{
bool flag = false;
if(isEqual(a.start, b.start) && isEqual(a.end, b.end))
{
flag = true;
}
return flag;
}
bool isInvectorOfGraph(Graph g, vector<Graph> *vg)//判断Graph g 是否在vector里面
{
bool flag = false;
for(int i = 0; i < (*vg).size(); i++)
{
if(isEqualGraph(g, (*vg)[i]))
{
flag = true;
}
}
return flag;
}
void PrintfNodeVector(vector<Node>* Vn)
{
for(int i = 0; i < (*Vn).size(); i++)
{
printf("nodevector<%d>.engine:%s\n",i,(*Vn)[i].engine.c_str());
printf("nodevector<%d>.pin:%d\n",i,(*Vn)[i].pin);
printf("nodevector<%d>.inout:%d\n",i,(*Vn)[i].inout);
}
}
void PrintfGraphVector(vector<Graph>* Vg)
{
Graph dispart;//分隔符
dispart.start.engine = "-10";
dispart.start.pin=-10;
dispart.start.inout = in;
dispart.end.engine = "-10";
dispart.end.pin=-10;
dispart.end.inout = in;
int j = 1;
printf("This is the circle %d:\n", j);
for(int i = 0; i < (*Vg).size() - 1; i++)
{
if(isEqualGraph((*Vg)[i], dispart)&&(i != (*Vg).size() - 1))
{
j++;
printf("This is the circle %d:\n", j);
}
else
{
printf("nodevector<%d>.startengine:%s\n",i,(*Vg)[i].start.engine.c_str());
printf("nodevector<%d>.startpin:%d\n",i,(*Vg)[i].start.pin);
printf("nodevector<%d>.startinout:%d\n",i,(*Vg)[i].start.inout);
printf("nodevector<%d>.endengine:%s\n",i,(*Vg)[i].end.engine.c_str());
printf("nodevector<%d>.endpin:%d\n",i,(*Vg)[i].end.pin);
printf("nodevector<%d>.endinout:%d\n\n",i,(*Vg)[i].end.inout);
}
}
}
void CreatVectorGraph(vector<Graph> *Vg)
{
Graph a[10];
a[0].start.engine = "1";
a[0].start.pin = 0;
a[0].start.inout = out;
a[0].end.engine = "2";
a[0].end.pin = 1;
a[0].end.inout = in;
a[1].start.engine = "2";
a[1].start.pin = 2;
a[1].start.inout = out;
a[1].end.engine = "3";
a[1].end.pin = 1;
a[1].end.inout = in;
a[2].start.engine = "3";
a[2].start.pin = 2;
a[2].start.inout = out;
a[2].end.engine = "4";
a[2].end.pin = 0;
a[2].end.inout = in;
a[3].start.engine = "4";
a[3].start.pin = 1;
a[3].start.inout = out;
a[3].end.engine = "1";
a[3].end.pin = 1;
a[3].end.inout = in;
a[4].start.engine = "2";
a[4].start.pin = 2;
a[4].start.inout = out;
a[4].end.engine = "1";
a[4].end.pin = 0;
a[4].end.inout = in;
a[5].start.engine = "1";
a[5].start.pin = 1;
a[5].start.inout = in;
a[5].end.engine = "1";
a[5].end.pin = 0;
a[5].end.inout = out;
a[6].start.engine = "2";
a[6].start.pin = 1;
a[6].start.inout = in;
a[6].end.engine = "2";
a[6].end.pin = 2;
a[6].end.inout = out;
a[7].start.engine = "3";
a[7].start.pin = 1;
a[7].start.inout = in;
a[7].end.engine = "3";
a[7].end.pin = 2;
a[7].end.inout = out;
a[8].start.engine = "4";
a[8].start.pin = 0;
a[8].start.inout = in;
a[8].end.engine = "4";
a[8].end.pin = 1;
a[8].end.inout = out;
for(int i = 0; i < 9; i++)
{
(*Vg).insert((*Vg).end(),a[i]);
}
}
void AddVectorGraph(vector<Graph> *Vg, vector<Node> *Vn)//得到最终抽象数据结构的边表vector和结点vector
{
int size = (*Vg).size();
vector<Node> vectorNode;
Graph test[2];
Node testNode[2];
int i;
for(i = 0; i < size; i++) //从边表vector里分离出来结点,存在结点vector里面
{
if(!isInvector((*Vg)[i].start, &vectorNode))
{
vectorNode.push_back((*Vg)[i].start);
}
if(!isInvector((*Vg)[i].end, &vectorNode))
{
vectorNode.push_back((*Vg)[i].end);
}
}
vector<Node> vectorN;
for(i = 0; i <vectorNode.size(); i++)//增加虚拟边到graphvector
{
if(!isInvector(vectorNode[i], &vectorN))
{
vectorN.push_back(vectorNode[i]);
test[0].start = vectorNode[i];
test[0].start.inout = in;
test[0].end = vectorNode[i];
test[0].end.inout = out;
if(!isInvectorOfGraph(test[0], Vg))
{
(*Vg).push_back(test[0]);
}
test[1].start = vectorNode[i];
test[1].start.inout = out;
test[1].end = vectorNode[i];
test[1].end.inout = in;
if(!isInvectorOfGraph(test[1], Vg))
{
(*Vg).push_back(test[1]);
}
}
}
vectorN.clear();
for(i = 0; i < vectorNode.size(); i++)//增加虚拟结点到Nodevector
{
if(!isInvector(vectorNode[i], &vectorN))
{
testNode[0] = vectorNode[i];
testNode[0].inout = in;
testNode[1] = vectorNode[i];
testNode[1].inout = out;
vectorN.push_back(testNode[0]);
vectorN.push_back(testNode[1]);
(*Vn).push_back(testNode[0]);
(*Vn).push_back(testNode[1]);
}
}
}
bool nodeIsInCircleofone(vector<Graph> *Vg ,Node n, vector<Graph> *gvoid, vector<Node> *nvoid, Node before, Node prebefore, Node test, vector<Node>* nodesavecircle, vector<Graph>* graphsavecircle)//对于给定的结点n,判断是否在环上, 深度优先搜索算法
{
bool flag = false;
Node now;
now = n;
for(int i = 0; i < (*Vg).size(); i++)
{
//printf("************if else**********%d %d\n",i,(isEqual((*Vg)[i].start,now) && !isEqual((*Vg)[i].end, before) && !isInvectorOfGraph((*Vg)[i], gvoid) && !isInvector((*Vg)[i].end, nvoid)));
//printf("(*Vg)[i].start end%d %s\n",i,(*Vg)[i].start.engine.c_str());
//printf("(*Vg)[i].start end%d %d\n",i,(*Vg)[i].start.pin);
//printf("(*Vg)[i].start end%d %d****%s %d %d\n",i,(*Vg)[i].start.inout,now.engine.c_str(), now.pin,now.inout);
//printf("(*Vg)[i].end %d %s\n",i,(*Vg)[i].end.engine.c_str);
//printf("(*Vg)[i].end %d %d\n",i,(*Vg)[i].end.pin);
//printf("(*Vg)[i].end %d %d\n",i,(*Vg)[i].end.inout);
//printf("***********************************\n");
if(isEqual((*Vg)[i].start,now) && !isEqual((*Vg)[i].end, before) && !isInvectorOfGraph((*Vg)[i], gvoid) && !isInvector((*Vg)[i].end, nvoid))
{
(*gvoid).push_back((*Vg)[i]);
(*nvoid).push_back((*Vg)[i].end);
(*nodesavecircle).push_back((*Vg)[i].end);
(*graphsavecircle).push_back((*Vg)[i]);
prebefore = before;
before = now;
now = (*Vg)[i].end;
//printf("now end%d %s\n",i,now.engine.c_str());
//printf("now end%d %d\n",i,now.pin);
//printf("now end%d %d\n",i,now.inout);
//printf("test %d %s\n",i,test.engine.c_str());
//printf("test %d %d\n",i,test.pin);
//printf("test %d %d\n",i,test.inout);
if(isEqual(test, now))
{
flag = true;
//printf("********\n");
return flag;
}
if(nodeIsInCircleofone(Vg, now, gvoid, nvoid, before, prebefore, test, nodesavecircle, graphsavecircle) == true)
{
flag = true;
return true;
}
else
{
now = (*Vg)[i].start;
before = prebefore;
(*nodesavecircle).pop_back();
(*graphsavecircle).pop_back();
}
}
}
return flag;
}
void GetAllNodeInCircle(vector<Graph> *Vg , vector<Node> *Vn, vector<Node> *result, vector<Graph>* vectorGraphResult)//找出Vn中所有在环上的点
{
Node before, prebefore;
before.engine = -1;
before.inout = in;
before.pin = -1;
vector<Graph> gvoid;
vector<Node> nvoid;
vector<Node> nodesavecircle;
vector<Graph> graphsavecircle;
Graph dispart;
dispart.start.engine = -10;
dispart.start.pin=-10;
dispart.start.inout = in;
dispart.end.engine = -10;
dispart.end.pin=-10;
dispart.end.inout = in;
//PrintfNodeVector(Vn);
//PrintfGraphVector(Vg);
for(int i = 0; i < (*Vn).size(); i++)
{
if(!isInvector((*Vn)[i], &nodesavecircle))
{
// nodesavecircle.clear();
nodesavecircle.push_back((*Vn)[i]);
if(nodeIsInCircleofone(Vg , (*Vn)[i], &gvoid, &nvoid, before, prebefore, (*Vn)[i], &nodesavecircle, &graphsavecircle))
{
//(*result).push_back((*Vn)[i]);
graphsavecircle.push_back(dispart);
//printf("**** %d\n",i);
}
gvoid.clear();
nvoid.clear();
nodesavecircle.pop_back();
}
}
for(int j = 0; j < nodesavecircle.size(); j++)
{
(*result).push_back(nodesavecircle[j]);
}
for(int k = 0; k < graphsavecircle.size(); k++)
{
(*vectorGraphResult).push_back(graphsavecircle[k]);
}
}
int main(int argc, char* argv[])
{
vector<Graph> vectorGraph;//存储所有边的容器
vector<Node> vectorNode;//存储所有结点的容器
vector<Node> vectorNodeResult;//存储环上结点的容器
vector<Graph> vectorGraphResult;//存储环上所有边的容器
CreatVectorGraph(&vectorGraph);//创建原始 graphvector,包括引擎内部的结点连线
AddVectorGraph(&vectorGraph, &vectorNode);//将新增的虚拟出来的结点及有向边加入各自对应的容器
GetAllNodeInCircle(&vectorGraph, &vectorNode, &vectorNodeResult, &vectorGraphResult);//将所有在环上的点放入vectorNodeResult容器里 将所有环上的边存储(以环为单位)在vectorGraphResult容器里
//printf("vectorNodeResult.size:%d\n", vectorNodeResult.size());
//printf("vectorGraphResult.size:%d\n", vectorGraphResult.size());
//PrintfNodeVector(&vectorNodeResult);
PrintfGraphVector(&vectorGraphResult);
printf("Hello World!\n");
return 0;
}