Java:拥有一个项目集合,其中每个项目都有一个字段“previousItem”,订购集合的最有效方法是什么?

时间:2012-03-12 09:07:12

标签: java collections hierarchical-data

我在未排序的集合中有一组分层项目。每个项目都有一个字段previousItem:

public class Item{
   public Item previousItem;
}

处理这些项目的最有效方法是什么,以便输出是一个集合,其中没有任何previousItem的Item是集合中的第一个Item,每个后续项目的previousItem是集合中的上一个项目?

我的第一个想法是在Item类中实现Comparable接口:

public int compareTo(Item that) {
    final int BEFORE = -1;
    final int EQUAL = 0;
    final int AFTER = 1;

    if(this.previousItem==null){
        return BEFORE;
    }

    if(that.previousItem==null){
        return AFTER;
    }

    if(this.previousItem.equals(that){
        return AFTER;
    }else if(that.previousItem.equals(this){
        return BEFORE;
    }

    return EQUAL;
}

然后遍历项目并将它们添加到TreeSet:

SortedSet<Item> itemSortedSet = new TreeSet<Item>();
for (Item item : itemCollection) {
    itemSortedSet.add(item);
}

是否有一种更有效的方式(处理所需的时间更少/需要的迭代次数)来对集合进行排序,使它们处于逻辑层次顺序?

4 个答案:

答案 0 :(得分:6)

你的比较器不起作用:它不提供传递性,即如果在A-> B-> C的情况下比较项目A和C,它将做错误的事。

如果没有项目可以包含相同上一项,则Item对象基本上构成基本链接列表。如果您碰巧知道哪一个是最后一项,您可以从那里开始一个循环并解开整个结构:

Item last = ...;

while (last != null) {
    result.add(last)
    last = last.previousItem
}

如果您无法找到最后一个项目,那么您可以使用IdentityHashMap将每个previousItem值映射到使用它的Item对象:

IdentityHashMap<Item,Item> m = new IdentityHashMap<Item,Item>(itemset.size());

for (Item i : itemset)
    m.put(i.previousItem, i);

Item i = m.get(null);

while (i != null) {
    result.add(i);

    i = m.get(i);
}

这将从没有上一个节点的项开始解析未分类的集合。

这两种方法都具有大致线性的复杂度w.r.t。项目数量,但他们做出两个假设,在您的情况下可能无效:

  • 每个项目只能是最多一个其他节点的前一项,即您的项目是列表而不是树。

  • 项目中只有一个“线程”。

如果这些假设中的任何一个无效,您将需要一个更复杂的算法来对其进行排序。

答案 1 :(得分:0)

从我看到的,你的Item已经实现了一个链表(如果不是通过名字),所以将它放入一个集合的自然(对我来说)的方式是将它转换为一个真实的列表递归。转换项目后,您可能需要根据您的规范撤消列表。

public class Item {
   Item previousItem;

   public void putToCollection(ArrayList<Item> list) {
     list.add(this);
     if (previousItem == null) {
       Collections.reverse(list);
     } else {
       previousItem.putToCollection(list);
     }
   }
}

答案 2 :(得分:0)

如果我理解正确,你就可以在Item对象上找到没有前一个对象的句柄。您可以循环遍历Items(例如,使用while循环)并将它们添加到ArrayList或LinkedList,因为add() - 这些List实现的方法只是在列表的末尾附加一个新Item。这样,你就可以在O(n)-time中完成它。

答案 3 :(得分:0)

您可以使用最初放置所有项目的HashSet<Item>。然后,您循环浏览项目并从集合中删除每个previousItem。最后,您应该在集合中留下一个元素,最后一个元素,对于任何其他项目,它不是previousItem。然后,您只需添加从该项开始并通过链接的项目。