【问题标题】:java - TreeMap lower/higher gettersjava - TreeMap 较低/较高的吸气剂
【发布时间】:2015-06-18 08:58:18
【问题描述】:

也许我的逻辑有点停止工作,但我发现这种行为令人困惑。假设我有一个 TreeMap 如下:

  TreeMap<Integer, Double> map = new TreeMap<Integer, Double>(Collections.reverseOrder());
    map.put(123, 0.5);
    map.put(678, 1.0);
    map.put(567, 0.1);

    int key = 100;

现在,我想使用 map.lowerEntry(key) 并根据 getter 的文档:

返回与严格小于给定键的最大键关联的键值映射,如果没有这样的键,则返回 null。

我希望 null 作为结果,但系统调用 System.out.println("Lower than "+key+ " is "+map.lowerEntry(key)); 会产生 Lower than 100 is 123=0.5。如果我使用 map.higherEntry(key) 记录为

返回与严格大于给定键的最小键关联的键值映射,如果没有这样的键,则返回 null。

然后我得到了想要的结果,但根据文档,它是违反直觉的。我猜想在 TreeMap 上调用 Collections.reverseOrder() 比较器会反转地图内部应用的逻辑?

编辑 使用 TreeSet 在使用 Collections.reverseOrder() 比较器初始化时,我得到一致的行为(关于函数名称):

TreeSet<Integer> set = new TreeSet<Integer>(Collections.reverseOrder());
    set.add(123);
    set.add(678);
    set.add(567);

int key = 200;
System.out.println("Lower than "+key+ " is "+set.tailSet(key));

产生Lower than 200 is [123],这是我所期望的。 TreeMap和TreeSet之间的这种不一致是否正常?有人可以请解释一下吗?谢谢你。

【问题讨论】:

  • 当然Collections.reverseOrder() 会颠倒低/高的定义——正如名字所说的那样。
  • 嗯,我想应该在文档中指定,或者应该放置一个标志,以防顺序颠倒以保持一致性
  • 请记住reverseOrder() 只是Comparator 的一个特殊实现,它将反转键的自然顺序(由它们的compareTo() 实现定义)。对于多种情况,可能有多种不同的比较器或可比较的实现,您无法在树实现甚至文档中处理所有这些情况。事实上,树形图甚至不知道您传递的比较器反转了顺序。
  • 正如我所说,tailSet() 返回比较器定义的“更高”值。因此它类似于higherEntry()(你从低到高或从头到尾迭代)。错误在于这里使用tailSet() 而不是headSet()
  • 井头 = 前,尾 = 后。如果您遍历一个有序列表,您通常从定义较低值的前面开始(即,在大多数情况下默认为升序迭代),因此 head->tail = lower->higher。如多次所述:这完全取决于“较低”的定义,在反向比较器的情况下,它与默认值相反。

标签: java reverse treemap


【解决方案1】:

我将尝试“总结”上面的 cmets 以获得一些结构:

TreeMap.lowerEntry(key)TreeSet.headSet(key) 具有基本相同的行为,即它们返回低于键的元素。 TreeMap.higherEntry(key)TreeSet.tailSet(key) 也是如此。

在它们中的任何一个上使用反向比较器都会导致顺序颠倒,即高变低,低变高。当键/元素是数字等时,这可能看起来违反直觉,但颠倒它们的排序顺序也是如此。

如果为元素添加一些语义,可能会更容易理解:

假设我们正在处理一个票务系统,该系统会计算错误的发生次数,而有人定义了要修复的错误的优先级。

现在您想要遍历该错误列表并显示它们,因此您使用TreeMap&lt;Integer, ErrorDescription&gt; 对它们进行排序。

根据键的语义,您将使用不同的比较器:

  • 如果关键是优先级,通常的概念是较低的数字意味着较高的优先级,您只需将地图从最小到最高数字排序,即您只需使用标准顺序。
  • 如果关键是出现次数,您很可能希望出现次数最多的错误位于列表的首位,因此您可以使用相反的顺序。但是,由于整数被定义为从小到大排序,因此您需要使用反向比较器。

最后,引用您上一条评论:

我发现函数的文档和/或名称具有误导性。

如果您考虑上面的示例,仅向数字添加语义会改变“较低”和“较高”的含义。另外考虑到数字键只是一种类型的键,您还可以使用日期、字符串、枚举或许多其他具有自然顺序的对象(因此实现Comparable)或需要在案例中排序-逐案处理(因此使用Comparator)。

由于文档必须适用于许多不同的情况,因此很难以适合所有情况的方式编写它。 “较低”和“较高”的含义取决于具体情况,因此最简单的方法是使用该措辞并将语义的解释留给开发人员。

【讨论】:

    【解决方案2】:

    可能你想要的答案就在这里:TreeMap(Comparator&lt;? super K&gt; comparator)constructor

    构造一个新的空树图,根据给定的比较器排序...

    参数:

    comparator - 将用于订购此地图的比较器。如果为 null,则将使用键的自然顺序。

    那么,小于大于只针对这个comparator

    此外,正如 Thomas 所指出的,您可能对 tailSet(key) 的含义感到困惑。从文档中,它应该为您提供 大于或等于 键的元素。因此,以相反的顺序,您会得到较低的值。

    【讨论】:

    • 嗨,dejvuth。谢谢你的时间。无论java文档如何,你能否合理地解释一下tailSet和headSet对你来说是什么
    • tailSetheadSet 给你一个SortedSet,它从头到尾为你的元素排序。在自然排序中,它是升序。
    猜你喜欢
    • 1970-01-01
    • 2018-11-16
    • 2018-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 2019-11-26
    相关资源
    最近更新 更多