【问题标题】:Find element in deep hierarchy - iteration vs recursion在深层层次结构中查找元素 - 迭代与递归
【发布时间】:2015-03-15 11:32:00
【问题描述】:

我的菜单层次结构如下所示:

Root
    ProductGroups
        Products
            ItemTypes
                Items

我避免了循环引用,因此只有从父级到子级的引用,例如ProductGroup 引用其产品。

如果我想知道某个项目属于哪个产品,我必须从根开始遍历层次结构。这会产生 5 个 for 循环:

for (MenuElement rootChild : Root.getChildren())
 for(ProductGroup group : rootChild.getChildren())
  for(Product product: group.getChildren())
   for(ItemType itemType : product.getChildren())
    for(Item item : itemType.getChildren())
     if(item == searchedItem)
      return product;

这是最好的方法还是您认为递归方法更好?

性能应该没有问题:10 个 ProductGroups、10 个产品、6 个 ItemTypes、~30 个 Items,因此递归方法不会导致大的过载。

递归的一个参数是更短的代码。在这种特定情况下还有更多吗?

【问题讨论】:

标签: java recursion iteration hierarchy circular-reference


【解决方案1】:

如果您只是经常调用它,我建议您在每个级别都包含一个父指针,或者如果您不想修改代码,请创建用于反向查找的哈希图,而不是使用您的任何一个解决方案。

Item->ItemType
ItemType->Product
Product->ProductGroup

您当前的解决方案总是遍历所有现有项目,这有点矫枉过正。如果您进行反向查找,您将在 2 从 hashmap 获取后完成,并且您的代码会像这样简单得多:

type = itemToTypeMap.get(item);
if (null == type); //treat error
product = typeToProductMap.get(type);
if (null == product); //treat error
return product;

【讨论】:

  • 是的,父指针会简化它,但这将是一个循环引用。我认为这更糟?但是 HashMap 是一个很好的解决方案,谢谢。
  • 我认为如果您能解释一下您认为“循环”引用的问题是什么,那将非常有帮助。我不会将父指针描述为循环的,而是双向的。
【解决方案2】:

我不知道递归方法将如何工作,因为您在每个级别都有不同的类型,而且我们对这些类型或任何超类型等了解不够。

我可以给出的一条建议是关于耦合。

您的代码违反了Law of Demeter,因为此代码与这些内部结构中的每一个都存在高度耦合。这使得以后难以重构或扩展。

这段代码更松耦合:

for (MenuElement rootChild : Root.getChildren()) {
   Product product = rootChild.findProductByItem(searchedItem);
   if (product != null) return product;
}

然后在MenuElement:

public Product findProductByItem(Item item) {
   for (ProductGroup group : getChildren()) {
     Product product = group.findProductByItem(item);
     if (product!=null) return product;
   }
   return null;
}

然后在ProductGroup:

public Product findProductByItem(Item item) {
   for (Product product: getChildren())
     if (product.matchesItem(item))
        return product;
   return null;
}

然后在Product:

public boolean matchesItem(Item item) {
   for (ItemType itemType : getChildren())
     if (itemType.matches(item))
       return true;
   return false;
}

然后在ItemType:

public boolean matchesItem(Item searchItem) {
     for (Item item : getChildren())
       if (item == searchItem) //do you really mean == BTW?
         return true;
   return false;
}

现在您可以看到可能适合拉起超类的重复模式,这可以帮助您实现递归代码。

【讨论】:

  • 违反得墨忒耳法则?但父母只知道他们的孩子,而不是相反。或者你的意思是因为我使用的是自上而下的引用而不是自下而上的?
  • 我说的是您发布的代码。它与所有级别和所有类耦合。
猜你喜欢
  • 2013-01-21
  • 2021-06-15
  • 2013-11-22
  • 2017-02-04
  • 2015-11-23
  • 1970-01-01
  • 2014-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多