Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在对象层次结构中查找周期?_Java_Algorithm_Cyclomatic Complexity_Object Graph - Fatal编程技术网

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


请注意,此算法甚至可以在公司抽象之外实现(如本例中),因为它在每次调用中传播公司对象作为遍历状态的一部分(以及集合)。这不是强制性的,因为这些方法本身可能是公司抽象的一部分,但必须将集合作为输入参数传播。

编写此方法时最好抛出异常