任何集合O1indexOf时间复杂度?

问题描述

谁能帮助我弄清楚,java中是否有任何集合类型(或任何语言激动性的集合类型)为indexOf(Item item)操作提供O(1)时间复杂度? [您可以假设没有重复项,或者只是第一个要返回的索引]

如果什么都没有,谁能帮我推断出没有形成的原因吗?有什么特殊原因吗?

解决方法

没有具有该属性的Java(标准)集合类型。

indexOf(Object)方法是在List中声明的,没有List实现比O(N)查找更好。

还有其他集合类型提供O(logN)O(1)查找,但是它们不像indexOf(Object)那样返回位置(和索引)。 ({HashMapHashSet分别提供get(key)的{​​{1}}和contains(object)。)


如果什么都没有,谁能帮助我推断出没有形成这种现象的原因吗?有什么特殊原因吗?

因为提供了这样功能的数据结构会很复杂,并且(可能)变慢和/或合并O(1)ArrayList的缺点。

我想不出一种的方法来实现具有快速查找的列表;即没有严重缺陷的产品。如果有一个好的方法,我希望Java团队知道它……并将它包含在Java SE库中。这类似于为什么没有通用的 concurrent 列表类型。

问题是设计通用收集类型涉及折衷。当针对一种访问方式进行优化时,针对另一种访问方式进行了非优化。看来。

,

要在O(1)中的集合中查找元素的索引,您需要能够直接检索元素的索引而无需搜索。 Listarray不允许我们这样做(需要O(N)),并且Set的排序没有 1 。>

我们剩下一个Map,但Map是一个键值对。

您可以创建一个映射,其中键作为元素,值作为索引,作为集合的辅助数据结构。缺点是您需要在更新集合(列表/数组)时更新地图

或者只是使用地图并删除您的收藏集。


1 indexOf方法在List上,而不在Collection上。

,

地图似乎是最简单的解决方案,但只是为了好玩:(剩下的List的实现留给读者练习)

package org.example;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

public class HashList<E> {
    private final List<E> list = new ArrayList<>();
    private final Map<E,Set<Long>> indexes = new HashMap<>();

    public long indexOf(E item) {
        Set<Long> indexSet = indexes.get(item);
        if (indexSet == null || indexSet.isEmpty()) {
            return -1;
        } else {
            return indexSet.iterator().next();
        }
    }

    public void add(E item) {
        list.add(item);
        long index = list.size() - 1;
        Set<Long> indexSet = indexes.get(item);
        if (indexSet == null) {
            indexSet = new TreeSet<>();
            indexes.put(item,indexSet);
        }
        indexSet.add(index);
    }

    public static void main(String... args) {
        HashList<String> list = new HashList<>();

        assertTrue(list.indexOf("foo") == -1);
        list.add("foo");
        assertTrue(list.indexOf("foo") == 0);
        list.add("bar");
        assertTrue(list.indexOf("bar") == 1);
        list.add("foo");
        // still 0 for the first occurrence
        assertTrue(list.indexOf("foo") == 0);
    }

    private static void assertTrue(boolean truth) {
        if (!truth) {
            throw new RuntimeException();
        }
    }
}