Java 如何在对象层次结构中查找周期?
有一个类Java 如何在对象层次结构中查找周期?,java,algorithm,cyclomatic-complexity,object-graph,Java,Algorithm,Cyclomatic Complexity,Object Graph,有一个类Company,该类引用了Company的另一个实例,以表示父对象。假设有四家公司c1,c2,c3和c4和c2,c3,c4将母公司设置为c1 例如: public class Company { public Company parent; public Company() { } public Company(Company parent) { this.parent = parent; } public static void main(String[
Company
,该类引用了Company
的另一个实例,以表示父对象。假设有四家公司c1
,c2
,c3
和c4
和c2
,c3
,c4
将母公司设置为c1
例如:
public class Company {
public Company parent;
public Company() { }
public Company(Company parent) {
this.parent = parent;
}
public static void main(String[] args) {
Company c1 = new Company();
Company c2 = new Company(c1);
Company c3 = new Company(c1);
Company c4 = new Company(c1);
}
public void myMethod(Company c)
{
Set<Company> visitedCompanies=new HashSet<Company>();
visitedCompanies.add(c);
myPrivateMethod(c, visitedCompanies);
}
private void myPrivateMethod(Company c, Set<Company> visitedCompanies)
{
if (visitedCompanies.contains(c))
{
// Cylce detected
}
else
{
//... do some stuff
// Go upwards in the hierarchy
if (c.getParent()!=null)
{
visitedCompanies.add(c);
myPrivateMethod(c.getParent(), visitedCompanies);
}
}
如果我们将c2
设置为c1
的母公司:
c1.parent = c2;
然后,它将在公司层次结构中创建一个无限循环,这是我们必须在系统中避免的
我们希望能够在运行时检测此。在上述情况下,检查同一类对象的圈复杂度的最佳算法是什么?您可以将parent
设置为private
,并使用setParent(Company)
方法更改parent
的值。然后:
public boolean setParent(Company parent) {
Company curr = parent;
while (curr != null) {
if (curr.equals(this)) {
return false; // Failed as cycle
} else {
curr = curr.getParent();
}
}
this.parent = parent;
return true;
}
在一般情况下,使用public
变量会破坏封装,这是一种不好的做法
如果无法将字段更改为private
,则:
public List<Company> hasCycle(List<Company> companies) {
while (companies.size() > 0) {
List<Company> cycle = new ArrayList<Company>();
Company curr = companies.get(companies.length() - 1);
cycle.add(curr);
while (curr.parent != null) {
curr = curr.parent;
if (cycle.contains(curr)) {
return cycle; // Cycle detected
}
cycle.add(curr);
}
companies.removeAll(cycle); // Remove all elements we traversed through just now
}
return null;
}
上市公司(上市公司){
而(companys.size()>0){
列表周期=新建ArrayList();
Company curr=companys.get(companys.length()-1);
循环。添加(当前);
while(curr.parent!=null){
curr=curr.parent;
if(循环包含(当前)){
返回周期;//检测到周期
}
循环。添加(当前);
}
companys.removeAll(cycle);//删除我们刚才遍历的所有元素
}
返回null;
}
编辑:将hasCycle
的返回更改为返回一个列表
,其中包含一个周期中的所有公司,以便进一步处理(打印、删除等)。您的任务与圈复杂度无关。你们的实体基本上形成了一个图形,你们想检测其中的循环。通常的方法是执行一个命令
你可以找到很多这样做的例子。我通过编程解决了这个问题,创建了一个处理对象的本地集,并让它在每次调用递归方法时作为输入参数传播
例如:
public class Company {
public Company parent;
public Company() { }
public Company(Company parent) {
this.parent = parent;
}
public static void main(String[] args) {
Company c1 = new Company();
Company c2 = new Company(c1);
Company c3 = new Company(c1);
Company c4 = new Company(c1);
}
public void myMethod(Company c)
{
Set<Company> visitedCompanies=new HashSet<Company>();
visitedCompanies.add(c);
myPrivateMethod(c, visitedCompanies);
}
private void myPrivateMethod(Company c, Set<Company> visitedCompanies)
{
if (visitedCompanies.contains(c))
{
// Cylce detected
}
else
{
//... do some stuff
// Go upwards in the hierarchy
if (c.getParent()!=null)
{
visitedCompanies.add(c);
myPrivateMethod(c.getParent(), visitedCompanies);
}
}
public void myMethod(c公司)
{
Set visitedCompanies=newhashset();
访问的公司。添加(c);
我的私人方法(c,参观公司);
}
私有void myPrivateMethod(公司c,设置访问公司)
{
if(访问公司。包含(c))
{
//检测到Cylce
}
其他的
{
//…做点什么
//在层次结构中向上
如果(c.getParent()!=null)
{
访问的公司。添加(c);
myPrivateMethod(c.getParent(),访问的公司);
}
}
当然,您必须首先确保您的类公司是可索引的:它正确地覆盖hashCode
和equals
请注意,此算法甚至可以在公司抽象之外实现(如本例中),因为它在每次调用中传播公司对象作为遍历状态的一部分(以及集合)。这不是强制性的,因为这些方法本身可能是公司抽象的一部分,但必须将集合作为输入参数传播。编写此方法时最好抛出异常