取决于实现 List 和 Map 的类。如果您使用的是实现 java.util.RandomAccess 的 List 类(即 ArrayList),那么对 get(i) 的调用是 O(1)。如果是 LinkedList,则为 O(n)。
-- 编辑后显示以下代码 sn-p(因为下面的 verdy_p 读起来不太好,而且喜欢离题):--
// In HashMap.java, line 867, JDK 1.6.0.24, how much more
// constant time do we want?
public Set<K> keySet() {
Set<K> ks = keySet;
return (ks != null ? ks : (keySet = new KeySet()));
}
-- 编辑结束--
在大多数 Map 实现中对 keySet() 的调用将是常数时间。
关于遍历 keySet() 如果您使用数组支持的 Map 实现(如 HashMap),keySet() 依赖于 entrySet(),它返回一个由数组支持的内部迭代器。所以keySet()的迭代是O(n)。
我还假设大多数(如果不是全部)由数组支持的 Map 实现都是这种情况。
对于 SortedMap 实现(如 TreeMap),对其键进行迭代类似于在树上从最低键到最大键进行迭代。这相当于一个失败的二分查找 O(n)。
这两种情况似乎都是 O(n)。如果您使用 Eclipse,您实际上可以查看实现 java 类的代码并更好地了解它们的复杂性。
对于 java.util.concurrent 下的类(如 ConcurrentHashMap),您必须考虑其他因素来确定它们的成本。
再扩展一点,如果你使用链表,list.get(i).keyset() 将是 O(n)。使用 ArrayList,它将是 O(1)。遍历键集将取决于您使用的是数组支持的 Map (HashMap) 还是 SortedMap (TreeMap)。在这两种情况下,遍历都将是 O(n),前者比后者快 显着,因为数组遍历总是比遍历指针(或此 Java 特定情况下的引用)更快。
现在,如果您考虑 both list.get(i).keySet() 和集合的迭代,使用链表实现,那将为 O(n^2)。因此,您应该使用迭代器而不是执行 list.get(i).keySet()(请参阅下面的 pseudocode,为了清楚起见,它避免了通用语法)
对于未实现 java.util.RandomAccess(如 LinkedList)的列表,这是 O(n^2):
for( int i = 0; i < list.size(); i++ )
{
Set keySet = list.get(i).keySet();
for( Integer key : keySet.iterator() )
{
... stuff (assuming constant time) ...
}
}
对于相同类型的 List 实现,这是 O(n):
for( Map m : list.iterator() )
{
for( Integer key : m.keySet() )
{
... stuff (assuming constant time) ...
}
}