2017-08-09 35 views
1

我正在尝试使用自定义比较器实现NavigableMap,该比较基于值而不是按键进行比较。我非常了解java和一般编码,所以如果我的术语是inccorect或代码可怕,请原谅我!我试图寻找类似的问题,试图复制解决方案,但我仍然recieving以下错误,当我尝试编译:NavigableMap - 基于值进行比较

java: no suitable constructor found for TreeMap(OrderLineSegments) 
    constructor java.util.TreeMap.TreeMap(java.util.Comparator<? super java.lang.Float>) is not applicable 
     (argument mismatch; OrderLineSegments cannot be converted to java.util.Comparator<? super java.lang.Float>) 
    constructor java.util.TreeMap.TreeMap(java.util.Map<? extends java.lang.Float,? extends java.lang.Float[]>) is not applicable 
     (argument mismatch; OrderLineSegments cannot be converted to java.util.Map<? extends java.lang.Float,? extends java.lang.Float[]>) 
    constructor java.util.TreeMap.TreeMap(java.util.SortedMap<java.lang.Float,? extends java.lang.Float[]>) is not applicable 
     (argument mismatch; OrderLineSegments cannot be converted to java.util.SortedMap<java.lang.Float,? extends java.lang.Float[]>) 

我想实现以下内容,其中浮法[]为4个float数组[ x1,y1,x2,y2]表示线段。

NavigableMap<Float, Float[]> segmentBST = new TreeMap<Float, Float[]>(new OrderLineSegments()); 

class OrderLineSegments implements Comparator<Map.Entry<Float, Float[]>> { 
public int compare(Map.Entry<Float, Float[]> a, Map.Entry<Float, Float[]> b) { 
    float ypos; 
    if (a.getValue()[1] < a.getValue()[1]) { 
     ypos = a.getValue()[1]; 
    } else { 
     ypos = b.getValue()[1]; 
    } 
    float ratioA = (a.getValue()[1] - ypos)/(ypos - a.getValue()[3]); 
    float ratioB = (b.getValue()[1] - ypos)/(ypos - b.getValue()[3]); 
    float posA = Math.abs(a.getValue()[0] - a.getValue()[2]) * ratioA + a.getValue()[0]; 
    float posB = Math.abs(b.getValue()[0] - b.getValue()[2]) * ratioB + b.getValue()[0]; 
    if (posA < posB) return 1; 
    if (posA > posB) return -1; 
    return 0; 
} 

我甚至不确定这是否是最好的方法来做到这一点,或者如果这是甚至可能,所以任何援助非常感谢。

+0

“比较器”用于比较*键*,因此'OrderLineSegments'需要实现'比较器'。因此,当您尝试比较Map.Entry时出错。 – Kayaman

+0

错误似乎很正常,因为文档说:'TreeMap的构造函数需要比较器',并且您提供了一个'比较器>'它不能像,不能反转键和值吗?如果您没有相同的值,则可能会更改 – azro

+0

您正在违反NavigableMap的合同。为什么不在这种情况下使用排序列表? – daniu

回答

0

您可以使用支持映射创建比较器作为单独的对象,然后在比较方法中获取来自同一映射的值。在此之后,您可以将您的逻辑应用到值... 您还需要使用覆盖的“放置”方法扩展树图,该方法将内容放入支持地图中,然后将其放入实际的可导航地图。

这些方针的东西:

public static void main(String[] args) throws IOException { 
    // Sun, 27 Jul 2014 10:19:10 +0100 

    class OrderLineSegments implements Comparator<Float> { 

     private Map<Float, Float[]> supportMap = new HashMap<>(); 

     public int compare(Float aKey, Float bKey) { 
      Float[] aValue = supportMap.get(aKey); 
      Float[] bValue = supportMap.get(bKey); 
      float ypos; 
      if (aValue[1] < bValue[1]) { 
       ypos = aValue[1]; 
      } else { 
       ypos = bValue[1]; 
      } 
      float ratioA = (aValue[1] - ypos)/(ypos - aValue[3]); 
      float ratioB = (bValue[1] - ypos)/(ypos - bValue[3]); 
      float posA = Math.abs(aValue[0] - aValue[2]) * ratioA + aValue[0]; 
      float posB = Math.abs(bValue[0] - bValue[2]) * ratioB + bValue[0]; 
      if (posA < posB) return 1; 
      if (posA > posB) return -1; 
      return 0; 
     } 

    } 

    OrderLineSegments orderLineSegments = new OrderLineSegments(); 

    class ExtendendNavigableMap extends TreeMap<Float, Float[]> { 

     private OrderLineSegments orderLineSegments; 

     public ExtendendNavigableMap(OrderLineSegments comparator) { 
      super(comparator); 
      orderLineSegments = comparator; 
     } 

     @Override 
     public Float[] put(Float key, Float[] value) { 
      orderLineSegments.supportMap.put(key, value); 
      return super.put(key, value); 
     } 
    } 

    NavigableMap<Float, Float[]> segmentBST = new ExtendendNavigableMap(orderLineSegments); 

    // Start adding elements 
    segmentBST.put(1.0F, new Float[]{0.1f, 0.2f, 0.3f, 0.4f}); 
    segmentBST.put(1.9F, new Float[]{0.3f, 0.2f, 0.3f, 0.4f}); 
    segmentBST.put(1.1F, new Float[]{-0.3f, 0.2f, 0.3f, 0.4f}); 

    segmentBST.forEach((k, v) -> System.out.printf("%s:%s%n", k, Arrays.toString(v))); 
} 

输出:

1.9:[0.3, 0.2, 0.3, 0.4] 
1.0:[0.1, 0.2, 0.3, 0.4] 
1.1:[-0.3, 0.2, 0.3, 0.4] 

虽然这种解决方案是令人费解的和丑陋的,它绝对应该工作。使用包含key和value的对象的树集更自然,然后使用您的问题中提出的实现逻辑为其创建自定义比较器。

+0

谢谢!现在正在编译。 尽管地图的排序似乎并未服从比较函数。 例如: 如果地图已包含:1.3283:1.3283,89.719,5.7766,70.22] 我补充一下:3.2011:3.2011,72.564,14.316,55.937] 应该插入到左边(即较低的位置)并且看起来像: {3.2011:[3.2011,72.564,14.316,55.937],1.3283:[1.3283,89.719,5.7766,70.22]} 但它被添加到右边(上位置)像这个: {1.3283:[1.3283,89.719,5.7766,70.22],3.2011:[3.2011,72.564,14.316,55.937]} – fortymod

+0

看来比较没有被调用。我在比较块中放置了一条println语句,没有打印任何内容。我认为这表明它没有被使用,并且正在使用自然键顺序?我还需要做些什么才能实现? – fortymod

+0

我的歉意,确实如此。我已经更新了答案。你能再次尝试一下代码吗?请让我知道,如果它适合你。 –