NavigableMap与SortedMap?

时间:2011-01-19 20:09:11

标签: java sorting dictionary

除了JVM版本之外,有没有理由使用SortedMap而不是NavigableMap? (NavigableMap自1.6以来一直存在; SortedMap自1.2以来一直存在

我正在尝试找到具有最大键的值,使得键< =引用键K0。我似乎无法弄明白如何使用SortedMap(如果它严格是<,那么我会调用headMap()然后调用lastKey()然后调用{{1} }),但NavigableMap.floorEntry()似乎正是我需要的。


澄清:就像一个例子,我正在处理具有不同行为模型的稀疏版本号范围。键可能是[0,2,5],因此版本号0和1由键#0处的值处理,版本号2-4由键#2处的值处理,版本号> gt; = 5由键#5处的值处理。

6 个答案:

答案 0 :(得分:9)

就个人而言,我非常相信使用最不具体的界面可以满足您的需求。这使您的意图更加清晰,对您可能的实施设置的限制更少。

大多数开发人员希望Sorted集合用于迭代目的,也许还需要随机访问性能。我看到很少有需要关闭元素的情况。

如果您需要该功能,请继续。我认为TreeMap实际上实现了NavigableMap。但是当你不需要它时,为什么限制自己呢?

答案 1 :(得分:8)

  

除了JVM版本之外,有没有理由使用SortedMap而不是NavigableMap?

是的,我可以想到一个例子。地图的提供者可能已将其与Collections.unmodifiableSortedMap包装在一起,因此即使源是TreeMap(实现NavigableMap),您也只能引用SortedMap和你不能把它投到NavigableMap

  

我正在尝试找到具有最大键的值,使得键< =引用键K0。我似乎无法弄清楚如何使用SortedMap

来做到这一点

有两种情况:地图包含密钥的完全匹配,或者不包含。因此,首先要查找完全匹配,只有当它不存在时,m.headMap(key).lastKey()才能给出正确答案。


这样做(虽然它没有真正的NavigableMap那么高效):

static <K, V> Map.Entry<K, V> floorEntry(final SortedMap<K, V> m, K key) {
    final SortedMap<K, V> tail; 
    if (m.containsKey(key)) {
        tail = m.tailMap(key);
    } else {
        SortedMap<K, V> head = m.headMap(key);
        if (head.isEmpty()) {
            return null;
        } else {
            tail = head.tailMap(head.lastKey());
        }
    }
    return tail.entrySet()
               .iterator()
               .next();
}

答案 2 :(得分:3)

使用整数时,可以使用x&lt; A + 1而不是x <= A,你已经完成了。我的意思是headMap(A + 1)等,应该做的工作。否则,我会选择finnw的解决方案,因为它比我能提出的任何内容都要清楚。

答案 3 :(得分:2)

我认为使用迭代器比使用headMap和tailMap更好,因为它效率不高。我测试了以下代码的情况,它运行良好,floorEntry2比floorEntry1快三倍。

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import java.util.*;
import java.util.Map.Entry;

import org.junit.Before;
import org.junit.Test;


class TestMapUtils <K,V> {

    public TestMapUtils()
    {

    }

    public Map.Entry<K, V> floorEntry1(final SortedMap<K, V> m, K key) {
        final SortedMap<K, V> tail; 
        if (m.containsKey(key)) {
            tail = m.tailMap(key);
        } else {
            SortedMap<K, V> head = m.headMap(key);
            if (head.isEmpty()) {
                return null;
            } else {
                tail = head.tailMap(head.lastKey());
            }
        }
        return tail.entrySet()
                   .iterator()
                   .next();
    }

    public Map.Entry<K, V> floorEntry2(final NavigableMap<K, V> m, K key) {
        Iterator<Map.Entry<K,V>> i = m.entrySet().iterator();
        Entry<K,V> tailEntry = null;
        if (key==null) {
            while (i.hasNext()) {
            Entry<K,V> e = i.next();
            if (e.getKey()==null)
                return null;
            }
        } else {
            while (i.hasNext()) {
            Entry<K,V> e = i.next();
                if (key.equals(e.getKey()))
                {
                    return e;
                }
                else
                {
                    if (((Integer) e.getKey()).intValue() < (((Integer) key).intValue())) {
                        tailEntry = e;
                    }
                }
            }
        }
        return tailEntry;
    }
}

public class TestSortedMap {

    protected TestMapUtils<Integer, Integer> testMapUtils;
    private NavigableMap<Integer, Integer> sortedMap;
    @Before
    public void setUp()
    {
        testMapUtils = new TestMapUtils<Integer, Integer>();
        sortedMap = addElementsToMap();
    }

    private NavigableMap<Integer, Integer> addElementsToMap() {
        NavigableMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
        map.put(10, 1);
        map.put(20, 2);
        map.put(30, 3);
        map.put(40, 4);
        map.put(50, 5);
        map.put(60, 6);
        return map;
    }

    @Test
    public void testFloorEntry()
    {

        long startTime1 = System.nanoTime();

        Entry<Integer, Integer> entry = testMapUtils.floorEntry2(sortedMap, 30);
        assertNotNull(entry);
        assertEquals(entry.getKey().intValue(), 30);

        entry = testMapUtils.floorEntry2(sortedMap, 60);
        assertNotNull(entry);
        assertEquals(entry.getKey().intValue(), 60);

        entry = testMapUtils.floorEntry2(sortedMap, 70);
        assertNotNull(entry);
        assertEquals(entry.getKey().intValue(), 60);

        entry = testMapUtils.floorEntry2(sortedMap, 55);
        assertNotNull(entry);
        assertEquals(entry.getKey().intValue(), 50);

        entry = testMapUtils.floorEntry2(sortedMap, 31);
        assertNotNull(entry);
        assertEquals(entry.getKey().intValue(), 30);

        entry = testMapUtils.floorEntry2(sortedMap, 0);
        assertNull(entry);



        long endTime1 = System.nanoTime() - startTime1;

        long startTime2 = System.nanoTime();

        entry = testMapUtils.floorEntry1(sortedMap, 30);
        assertNotNull(entry);
        assertEquals(entry.getKey().intValue(), 30);

        entry = testMapUtils.floorEntry1(sortedMap, 60);
        assertNotNull(entry);
        assertEquals(entry.getKey().intValue(), 60);

        entry = testMapUtils.floorEntry1(sortedMap, 70);
        assertNotNull(entry);
        assertEquals(entry.getKey().intValue(), 60);

        entry = testMapUtils.floorEntry1(sortedMap, 55);
        assertNotNull(entry);
        assertEquals(entry.getKey().intValue(), 50);

        entry = testMapUtils.floorEntry1(sortedMap, 31);
        assertNotNull(entry);
        assertEquals(entry.getKey().intValue(), 30);

        entry = testMapUtils.floorEntry1(sortedMap, 0);
        assertNull(entry);

        long endTime2 = System.nanoTime() - startTime2;

        if ( endTime2 > endTime1 )
        {
            System.out.println("First Execution is faster.. "+endTime1+", "+endTime2);
        } else if ( endTime1 > endTime2 ) {

            System.out.println("Second Execution is faster.. "+endTime1+", "+endTime2);
        } else {
            System.out.println("Execution times are same");
        }

    }

}

答案 4 :(得分:2)

  

除了JVM版本之外,有没有理由使用SortedMap而不是NavigableMap?

是的,如果您需要返回不可修改的地图而您没有使用Google Guava。

NavigableMap旨在取代SortedMap。 NavigableMap为SortedMap接口添加了经常需要的方法,Map实现者很容易添加,但是根据现有的SortedMap方法编写起来很尴尬。返回SortedMap而不是NavigableMap将导致代码的调用者不必要的工作。

很遗憾没有提供Collections.unmodifiableNavigableMap。 IMO这可能是一个疏忽,但在JDK 1.7中没有得到纠正,所以也许有人有理由不予理睬。我建议使用com.google.common.collect.Maps.unmodifiableNavigableMap

答案 5 :(得分:0)

“[NavigableMap]旨在取代SortedMap界面。” http://download.oracle.com/javase/6/docs/technotes/guides/collections/changes6.html

尽管如此,我同意Uri:使用最不具体的界面。