如果A->B,B->A,那么称A和B模块都存在循环依赖。
如果A->B,B->C,C->D,D->B,那么BCD存在循环依赖,A不存在循环依赖,以此类推
先输入若干模块之间的关系,判断某模块是否存在循环依赖。模块ID范围为0--0xffffffff
调用者保证相同的关系不重复输入
输入:
模块间关系,注意最后一行没有“,”结尾输出描述:
模块是否循环依赖,注意最后一行没有“,”结尾
样例:
输入:
{0x00, 0x01},{0x02, 0x03},
{0x03, 0x04}
输出:
{0x00, false},
{0x01, false},
{0x02, false},
{0x03, false},
{0x04, false}
代码(没有优化,只实现功能)
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <map>
#include <string>
#include <vector>
using namespace std;
multimap<unsigned int, unsigned int> orgD; // A -> B
map<unsigned int, string> fPrt;
map<unsigned int,int> N; // 保存所有的节点
map<unsigned int, bool> St; // 保存节点是否为有环
// 用来保存轨迹,如果1->2,那么就把1和2都加到里面,如果1->2, 1->3, 当访问完2的时候,把2去除,同时把3加到里面
vector<unsigned int> trace;
// 这个函数里面还增加代码,如果有环,就打印这个环
void gothrough( multimap<unsigned int, unsigned int>* pSrcD,
map<unsigned int, int>* pVist,
unsigned int vstNumtmp)
{
if ((*pVist).count(vstNumtmp) > 0 && (*pVist)[vstNumtmp] == 1) // 表示当前这个节点已经被访问过了,那么是存在环的
{
// 下面是添加打印每个环的程序,这个是有问题的
/*
vector<unsigned int>::iterator iteV;
iteV = find(trace.begin(), trace.end(), vstNumtmp);
if (iteV != trace.end())
{
auto idx = distance(begin(trace), iteV);
St[vstNumtmp] = true;
while (idx < trace.size())
{
printf("%d->",trace.at(idx));
idx++;
}
return;
}
*/
// 下面只是一个判断有无环的程序
vector<unsigned int>::iterator iteV;
iteV = find(trace.begin(), trace.end(), vstNumtmp);
if (iteV != trace.end())
{
St[vstNumtmp] = true;
return;
}
}
// 否则这个节点就没有被访问过
(*pVist)[vstNumtmp] = 1; // 把这个节点置为已经访问过了
trace.push_back(vstNumtmp); // 把这个节点存到数组里面
typedef multimap<unsigned int, unsigned int>::iterator CIT;
typedef pair<CIT, CIT> Rng;
Rng range = pSrcD->equal_range(vstNumtmp);
for (CIT i = range.first; i != range.second; i++)
{
vstNumtmp = i->second;
gothrough(pSrcD, pVist, vstNumtmp);
}
trace.pop_back();
}
void AddDependency(unsigned int Moduleld, unsigned int DependMoudleId)
{
orgD.insert(make_pair(Moduleld, DependMoudleId));
//orgD.insert(pair<unsigned int, unsigned int>(Moduleld, DependMoudleId));
//orgD[Moduleld] = DependMoudleId;
}
// 这个地方应该有误解,如果输入某个点的话,如果有环,那么在搜索的时候,肯定返回到这个地方,
// 所以在设计算法的时候,没有必要把所有的节点都判断一遍,只需要在输出的时候,调用这个函数即可,
// 要不然很麻烦
bool MoudleIsCycularDependency(unsigned int ModuleId)
{
if (orgD.count(ModuleId) == 0) // 如果在map的左边一列中找不到的话,那么肯定就不是有环的点
return false;
else if (St[ModuleId]) // 已经是true,就没必要再搞一遍了
return St[ModuleId];
else// 否则的话,就开始遍历,如果能回到这个点,就是有环的点,否则就不是有环的点
{
// 开始的时候所有节点没有被访问过
map<unsigned int, int> visit;
gothrough(&orgD, &visit, ModuleId);
if (St[ModuleId])
return true;
else
return false;
}
}
void clear(void)
{
orgD.clear();
fPrt.clear();
N.clear();
trace.clear();
St.clear();
}
int main()
{
while (1)
{
string orgS;
string tmp1, tmp2;
unsigned int T = 0;
while (getline(cin, orgS))
{
unsigned int ModuleID = 0, DependMoudleID = 0;
int i;
for (i = 3; orgS[i] != ','; i++)
{
ModuleID += ModuleID * 16 + orgS[i] - '0';
}
tmp1 = orgS.substr(1, i - 1);
fPrt[ModuleID] = tmp1;
int j;
for (j = i + 4; orgS[j] != '}'; j++)
{
DependMoudleID += DependMoudleID * 16 + orgS[j] - '0';
}
tmp2 = orgS.substr(i + 2, j - (i + 2));
fPrt[DependMoudleID] = tmp2;
AddDependency(ModuleID, DependMoudleID);
N[ModuleID] = 0; // 在数组的最后添加这个元素
N[DependMoudleID] = 0;
if (orgS[j + 1] != ',')
break;
}
map<unsigned int,int>::iterator it;
it = N.begin();
int toal = N.size();
for (; it != N.end(); it++)
{
toal--;
if (MoudleIsCycularDependency(it->first))
printf("{%s, true}", fPrt[it->first].c_str());
else
printf("{%s, false}", fPrt[it->first].c_str());
if (toal != 0)
printf(",\n");
else
printf("\n");
}
clear();
}
return 0;
}
我的一些测试用例:
// 有断点,无循环
{0x00, 0x01},
{0x02, 0x03},
{0x03, 0x04}
{0x00, false},
{0x01, false},
{0x02, false},
{0x03, false},
{0x04, false}
// 有断点、有循环
{0x00, 0x01},
{0x01, 0x03},
{0x02, 0x04},
{0x03, 0x00}
{0x00, true},
{0x01, true},
{0x02, false},
{0x03, true},
{0x04, false}
// 无断点、无循环
{0x00, 0x02},
{0x02, 0x03},
{0x03, 0x04}
{0x00, false},
{0x02, false},
{0x03, false},
{0x04, false}
// 有断点、两个循环
{0x01, 0x02},
{0x03, 0x01},
{0x02, 0x03},
{0x04, 0x09},
{0x07, 0x05},
{0x05, 0x06},
{0x06, 0x07}
{0x01, true},
{0x02, true},
{0x03, true},
{0x04, false},
{0x05, true},
{0x06, true},
{0x07, true},
{0x09, false}
// 两个循环、其中一个有个把
{0x01, 0x02},
{0x03, 0x01},
{0x02, 0x03},
{0x04, 0x05},
{0x07, 0x05},
{0x05, 0x06},
{0x06, 0x07}
{0x01, true},
{0x02, true},
{0x03, true},
{0x04, false},
{0x05, true},
{0x06, true},
{0x07, true}
// 有循环、节点后面有分叉
{0x05, 0x01},
{0x01, 0x02},
{0x02, 0x04},
{0x02, 0x03},
{0x03, 0x01}
{0x01, true},
{0x02, true},
{0x03, true},
{0x04, false},
{0x05, false}
// 无循环、节点后有分叉
{0x01, 0x02},
{0x02, 0x04},
{0x02, 0x03}
{0x01, false},
{0x02, false},
{0x03, false},
{0x04, false}
// 有循环、节点后有分叉
{0x01, 0x02},
{0x02, 0x04},
{0x04, 0x01},
{0x02, 0x03},
{0x03, 0x05}
{0x01, true},
{0x02, true},
{0x03, false},
{0x04, true},
{0x05, false}
// 几点后有分叉、无循环
{0x01, 0x03},
{0x02, 0x05},
{0x01, 0x06},
{0x02, 0x07}
{0x01, false},
{0x02, false},
{0x03, false},
{0x05, false},
{0x06, false},
{0x07, false}
// 有循环,节点后有很多分叉
{0x05, 0x01},
{0x01, 0x02},
{0x02, 0x03},
{0x03, 0x06},
{0x02, 0x04},
{0x04, 0x01},
{0x04, 0x07}
{0x01, true},
{0x02, true},
{0x03, false},
{0x04, true},
{0x05, false},
{0x06, false},
{0x07, false}
// 循环带个把
{0x05, 0x01},
{0x01, 0x02},
{0x02, 0x03},
{0x03, 0x01}
{0x01, true},
{0x02, true},
{0x03, true},
{0x05, false}
// 大循环包裹小循环
{0x01, 0x02},
{0x02, 0x03},
{0x03, 0x01},
{0x01, 0x04},
{0x04, 0x05},
{0x05, 0x01}
{0x01, true},
{0x02, true},
{0x03, true},
{0x04, true},
{0x05, true}
// 有循环、节点后有分叉
{0x01, 0x02},
{0x02, 0x03},
{0x02, 0x04},
{0x03, 0x01},
{0x05, 0x01}
{0x01, true},
{0x02, true},
{0x03, true},
{0x04, false},
{0x05, false}
// 交叉循环
{0x05, 0x01},
{0x01, 0x02},
{0x02, 0x03},
{0x03, 0x04},
{0x04, 0x01},
{0x03, 0x07},
{0x07, 0x06},
{0x06, 0x04}
{0x01, true},
{0x02, true},
{0x03, true},
{0x04, true},
{0x05, false},
{0x06, true},
{0x07, true}
// 交叉循环
{0x05, 0x01},
{0x01, 0x02},
{0x02, 0x03},
{0x03, 0x04},
{0x04, 0x01},
{0x07, 0x03},
{0x06, 0x07},
{0x04, 0x06}
{0x01, true},
{0x02, true},
{0x03, true},
{0x04, true},
{0x05, false},
{0x06, true},
{0x07, true}
// 两个循环相连
{0x05, 0x01},
{0x01, 0x02},
{0x02, 0x03},
{0x03, 0x04},
{0x04, 0x01},
{0x04, 0x06},
{0x06, 0x07},
{0x08, 0x06},
{0x07, 0x08}
{0x01, true},
{0x02, true},
{0x03, true},
{0x04, true},
{0x05, false},
{0x06, true},
{0x07, true},
{0x08, true}
// 两个无关的环,有把
{0x01, 0x02},
{0x02, 0x03},
{0x03, 0x02},
{0x03, 0x04},
{0x04, 0x02},
{0x07, 0x08},
{0x08, 0x09},
{0x07, 0x09},
{0x09, 0x07}
// 两个相连的环,有把
{0x01, 0x02},
{0x02, 0x03},
{0x03, 0x02},
{0x03, 0x04},
{0x04, 0x02},
{0x07, 0x08},
{0x08, 0x09},
{0x07, 0x09},
{0x09, 0x07},
{0x03, 0x07}
{0x01, false},
{0x02, true},
{0x03, true},
{0x04, true},
{0x07, true},
{0x08, true},
{0x09, true}