我需要一个支持3个操作的地图:“insert”,“remove”和“按排序顺序迭代”。这正是Java中TreeMap
的接口。也就是说,它也可以通过使用HashMap
来实现,并在每次迭代之前对其进行排序。为了分析不同的方法,让我说我执行n
插入和m
删除,'r'读取然后迭代。
使用TreeMap
,我们有以下实现:
TreeMap<Integer, Integer> tm = Maps.newTreeMap();
for (int i=0;i<n;++i) {tm.put(i, 2*i);} // O(n*log(n))
for (int i=0;i<m;++i) {tm.remove(i);} // O(m*log(m))
for (int i=0;i<r;++i) {tm.get(i);} // O(r*log(n-m))
for (Integer i : tm) {print(i);} // O(n-m)
总而言之,我们的总运行时间为O(n*log(n) + m*log(m) + r*log(n-m))
使用HashMap
,我们有以下实现:
HashMap<Integer, Integer> hm = Maps.newHashMap();
for (int i=0;i<n;++i) {hm.put(i, 2*i);} // O(n)
for (int i=0;i<m;++i) {hm.remove(i);} // O(m)
for (int i=0;i<r;++i) {hm.get(i);} // O(r)
List<Integer> sortedList = Lists.newArrayList(hm.keySet()); // O(n-m)
Collections.sort(sortedList); // O((n-m)*log(n-m))
for (Integer i : sortedList) {print(i);} // O(n-m)
总而言之,我们的总运行时间为O((n-m)*log(n-m))
。
适用于所有n,m O(n*log(n) + m*log(m) + r*log(n-m)) > O((n-m)*log(n-m))
。
因此,我的问题是,TreeMap
优于HashMap
的用例是什么?如果你需要遍历地图很多(比如说k
)次(在这种情况下,如果k
是&gt;&gt; log(n)
TreeMap
O(k*(n-m))
的运行时间,那会更好吗1}}将为HashMap
,而O(k*(n-m)*log(n-m)))
将为O(log(n))
?无论如何,如果您只执行HashMap
次迭代(这听起来像是一个理智的用例), TreeMap
将胜过{{1}}。我错过了什么吗?
答案 0 :(得分:4)
当然存在这样的用例。在所有读取繁重的设置中,您可以在插入过程中仅进行一次排序。与您的问题的假设相反,大多数用例都是重读。
当您需要提取键上限或下限的子图,找到最小或最大键,或查找最接近给定键的键时,TreeMap
提供了更大的优势。接口NavigableMap
专门用于这些操作。
答案 1 :(得分:1)
一个明显的用例是,您希望根据某些Comparator
定义对地图进行排序。它并不总是关于绩效。