【问题标题】:When to use TreeMap instead of HashMap何时使用 TreeMap 而不是 HashMap
【发布时间】:2023-03-20 10:34:01
【问题描述】:

我需要一个支持 3 种操作的地图:“插入”、“删除”和“按排序顺序迭代”。这正是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)) &gt; O((n-m)*log(n-m))

因此,我的问题是,TreeMapHashMap 更好的用例是什么?如果您需要多次迭代地图(比如说k),这是否更好(在这种情况下,如果k 是>> log(n) TreeMap 的运行时间将是O(k*(n-m)) 而对于HashMap 将是 O(k*(n-m)*log(n-m)))?不管怎样,如果您只执行 O(log(n)) 迭代(这听起来确实是一个合理的用例),HashMap 将优于 TreeMap。我错过了什么吗?

【问题讨论】:

标签: java collections


【解决方案1】:

当然存在这样的用例。在所有读取繁重的设置中,您具有在插入期间仅排序一次的优势。大多数用例阅读量很大,这与您问题的假设相反。

TreeMap 提供了更大的优势,当您需要提取具有上界或下界键的子图、查找最小或最大键或查找最接近给定键的键时。接口NavigableMap 专用于这些操作。

【讨论】:

  • 我编辑了我的问题以考虑阅读。 HashMap 中的读取是 O(1),而在 TreeMap 中它们在 O(log(n)) 中运行。
  • 我们在这里讨论迭代,所以“阅读”是指“在地图上迭代”。
  • 这是真的吗?哪个应用程序更频繁地迭代 Map 然后插入、删除和获取?我认为 get 将是最常见的操作,而不是迭代。如果迭代是最常见的操作,那么您将从 O(k*n) > O(n^2) 算法开始,该算法已经很笨拙。
  • 我明白为什么 NavigableMap 很有用,如果你想用树来实现它,那很好。我的问题是为什么 TreeMap 有用。
  • TreeMap implements NavigableMap.
【解决方案2】:

一个明显的用例是当您想要根据一些Comparator 定义对地图进行排序时。这并不总是与性能有关。

【讨论】:

  • OP 已经涵盖了:使用HashMap 并在迭代之前进行排序。
  • 您可以使用自定义比较器对map,keySet() 进行排序。
  • 我的意思是 OP 只关注性能方面。在某些情况下,首要要求不是性能,而是以某种有序的方式保存数据。
  • 没人关心你如何持有数据;我们关心您可以用它做什么。如果我给你一个内部有HashMap 的实现并在返回keySet 之前使用数组排序,你会像使用TreeMap 一样满意。
  • @MarkoTopolnik,我不认为你可以从这里的树上看到木头。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-16
  • 1970-01-01
  • 2013-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多