在数据结构ArrayList中高效搜索

时间:2013-06-24 15:03:50

标签: java android search data-structures quadtree

我有一个包含我的节点的ArrayList。节点具有源,目标和成本。现在我必须迭代整个ArrayList。这持续一段时间超过1000个节点。因此,我尝试按来源对列表进行排序。但是要在列表中找到相应的对,我尝试了二进制搜索。不幸的是,只有当我想要比较源或目标时才有效。但我必须比较两者以获得正确的一对。还有另一种搜索ArrayList的可能性吗?

5 个答案:

答案 0 :(得分:5)

不幸的是,没有。 ArrayList未被有效搜索。它们用于存储数据而不是搜索数据。如果你只想知道某个项是否被包含,我建议你使用HashSet,因为查找的时间复杂度为O(1)而不是O(n)的ArrayList(假设你已经实现了)对象的功能equals方法。)

如果您想快速搜索对象,我建议使用Dictionnary的实现,例如HashMap。如果您可以负担空间要求,您可以拥有多个地图,每个地图都有不同的密钥,无论您需要搜索什么密钥,都可以快速查找对象。请记住,查找还需要实现正确的equals方法。不幸的是,这要求每个密钥都是唯一的,这在您的情况下可能不是一个好主意。

但是,您可以使用HashMap为每个源存储具有键控源作为源的节点列表。您可以针对成本和目标执行相同的操作。这样,您可以减少需要迭代的节点数量。对于网络连接很少,这应该是一个很好的解决方案。

private HashMap<Source, ArrayList<Node>> sourceMap = new HashMap<Source, ArrayList<Node>>();
private HashMap<Target, ArrayList<Node>> targetMap = new HashMap<Target, ArrayList<Node>>();
private HashMap<Cost, ArrayList<Node>> costMap = new HashMap<Cost, ArrayList<Node>>();

/** Look for a node with a given source */
for( Node node : sourceMap.get(keySource) )
{
    /** Test the node for equality with a given node. Equals method below */
    if(node.equals(nodeYouAreLookingFor) { return node; }
}

为了确保您的代码有效,请务必覆盖equals方法。我知道我已经说过了,但这是一个非常常见的错误。

@Override
public boolean equals(Object object)
{ 
    if(object instanceof Node)
    {
        Node node = (Node) object;
        if(source.equals(node.getSource() && target.equals(node.getTarget()))
        {
            return true;
        }
    } else {
        return false;
    }
}

如果不这样做,测试只会根据您处理对象的方式比较可能相同或不相同的引用。

编辑:只需阅读您的平等基础。 equals方法应该在您的节点类中实现。但是,要使其工作,您还需要实现和覆盖源和目标的equals方法。也就是说,如果它们是对象。但请注意,如果它们Node也是ArrayList<Node> matchingNodes = sourceMap.get(desiredSourde).retainAll(targetMap.get(desiredTarget)); ,这可能会导致相当多的测试跨越整个网络。

更新:添加了代码以反映评论中代码的用途。

{{1}}

现在您有一个与源和目标条件匹配的所有节点的列表。如果您愿意牺牲一点内存,上面的查找将具有O(| sourceMap | *(| sourceMap | + | targetMap |))[1]的复杂性。虽然这优于所有节点的线性查找,O(| allNodeList |),如果你的网络足够大,我认为它有1000个节点,你可以获益很多。如果您的网络遵循自然发生的网络,那么正如Albert-LászlóBarabási所展示的那样,它可能是无标度的。这意味着将您的网络分成至少源和目标的列表(我没有证据证明这一点)会导致这些列表的无标度大小分布。因此,我相信查找源和目标的复杂性将大大减少为| sourceMap |和| targetMap |应该大大低于| allNodeList |。

答案 1 :(得分:1)

您需要将源和目标组合成一个比较器,例如

compare(T o1, T o2) {
    if(o1.source < o2.source) { return -1; }
    else if(o1.source > o2.source) { return 1; }
    // else o1.source == o2.source
    else if(o1.target < o2.target) { return -1; }
    else if(o1.target > o2.target) { return 1; }
    else return 0;
}

答案 2 :(得分:0)

您可以使用.compareTo()方法比较节点。

答案 3 :(得分:0)

您可以创建两个ArrayLists。第一个按源排序,第二个按目标排序。 然后,您可以使用相应列表上的binarySearch按源或目标进行搜索。

答案 4 :(得分:0)

您可以创建一个辅助类来存储源 - 目标对:

class SourceTarget {

    public final Source source; // public fields are OK when they're final and immutable.
    public final Target target; // you can use getters but I'm lazy
                                // (don't give this object setters. Map keys should ideally be immutable)

    public SourceTarget( Source s, Target t ){
        source = s;
        target = t;
    }

    @Override
    public boolean equals( Object other ){
        // Implement in the obvious way (only equal when both source and target are equal
    }

    @Override
    public int hashCode(){
        // Implement consistently with equals
    }
}

然后将您的东西存储在HashMap<SourceTarget, List<Node>>中,每个源 - 目标对映射到具有该源 - 目标对的节点列表。 要检索只是使用

List<Node> results = map.get( new SourceTarget( node.source, node.target ) );

除了制作助手类之外,您可以在Zim-Zam的答案中使用比较器,并使用代表TreeMap<Node,List<Node>>对象的Node作为SourceTarget对。