Java 是否有类似ListHashMap的数据结构?

Java 是否有类似ListHashMap的数据结构?,java,data-structures,Java,Data Structures,我一直在努力寻找一种数据结构,它将: 让我检查O(1)时间(哈希集)中的重复项 保留插入顺序,以及 请允许我获取该有序列表的子集 我找到的最接近的东西是LinkedHashSet,但它没有实现List接口,允许我调用List函数(比如subList)。我找不到这样的结构有什么原因吗?我即将实现我自己版本的LinkedHashSet,但改用ArrayList(与LinkedHashSet支持的链接列表相反)。我还从org.antlr.misc库中找到了OrderedHashSet,但由于没有实现所

我一直在努力寻找一种数据结构,它将:

  • 让我检查O(1)时间(哈希集)中的重复项
  • 保留插入顺序,以及
  • 请允许我获取该有序列表的子集 我找到的最接近的东西是
    LinkedHashSet
    ,但它没有实现
    List
    接口,允许我调用
    List
    函数(比如
    subList
    )。我找不到这样的结构有什么原因吗?我即将实现我自己版本的
    LinkedHashSet
    ,但改用
    ArrayList
    (与
    LinkedHashSet
    支持的链接列表相反)。我还从
    org.antlr.misc
    库中找到了
    OrderedHashSet
    ,但由于没有实现所需的子列表函数,这也存在不足。。。所以我真的很困惑为什么不需要这个?或者我只是没想到要找一个合适的名字

    编辑:我不仅试图找到一个现有的结构来满足这个要求,而且在没有的情况下,我试图找出它为什么不存在。谁能回答这个问题,谁就能得到公认的答案,因为我已经知道如何实现它:)


    编辑2:对不起,我应该更清楚我的第一个要求,我真的只需要检查副本真的有效。对我来说太晚了。

    数据结构不可能同时提供这些东西,它们是相互矛盾的:如果您在O(1)时间内插入和访问元素,这意味着它们是随机分布的(使用哈希代码),如果您想保留顺序,那么插入和访问将花费您更多的时间。 我相信你要找的是一个HashSet,而不是HashMap。这取决于插入的顺序对项目的未来是否至关重要,您可以使用HashSet(快速、随机访问和插入)或ArrayList(较慢,但保持顺序)。 我认为您不太可能创建一个满足您需求的数据结构。

    会有帮助吗


    不完全是O(1)(参考列表要求,第1点),但支持自然排序(第2点)和子集操作(第3点)。

    基本上,您所发现的是提供O(1)点查找但提供有效范围扫描(迭代)的东西。在数据库区域中,有时会调用这样的东西,其中的数据使用一些查找结构(如或)进行组织,但叶节点或索引项按特定顺序排序(在您的示例中,是按插入顺序排序)。下面显示了聚集B树的示例,其中@Itay Maman的解决方案是聚集散列索引的示例

    在Java中,没有这样的类能够满足您的需要,这可能是因为它的复杂性——很难(或几乎不可能)有一个这样的实现对所有工作负载都能起到最好的作用(例如,您多长时间执行一次范围扫描,多长时间执行一次点查找,它是否允许多个读卡器和多个写卡器?…等等),以下是一些可能的解决方案,取决于您的用例

  • 如果在大多数情况下,您并不真正关心项目3,那么请使用LinkedHashMap,并使用LinkedHashMap提供的正常迭代来执行项目3

  • 如果您关心所有这些项的性能,并且从不发布删除/更新,那么最简单的方法可能是同时使用HashMap和ArrayList将数据表示为聚集索引。每次插入都是对HashMap的插入+对ArrayList的追加,HashMap的值是ArrayList的索引。这将提供最佳的读取性能,但如果有更新/删除,则需要解决,可能需要将ArrayList替换为子数组的链接列表

  • 在极端情况下,您确实需要删除/更新,想要支持多线程访问,甚至想要持久性,那么最好使用开源嵌入式持久化键值存储,例如或,嵌入式键值存储用于快速存储,如RAM或闪存(这也有利于磁盘工作负载)虽然它们都是用C++实现的,但它们确实有java绑定(例如java中的RooSDB的介绍)

  • 。 当然,如果你同意重新实现一些东西,那么定制LinkedHashMap可能是最简单的。只需添加迭代器的另一个构造函数,它允许您在使用O(1)散列的任何特定条目处开始迭代。

    EDIT

    根据更新问题,您只需要无重复集合(与键值映射相反)。这稍微简化了一些事情。基本上,此解决方案使用: -确定重复性的(散列)集 -用于维护插入顺序的简单(数组)列表

    除此之外,还有一个用于子列表的列表的自定义实现。我必须推出自己的(而不是依赖
    ArrayList.subList()
    ),因为从
    ArrayList
    返回的(子)列表在创建后不允许数组列表更改其大小。幸运的是,在
    AbstractList
    的帮助下,这非常简单(只需重写两种方法)

    p1包;
    导入java.util.AbstractList;
    导入java.util.ArrayList;
    导入java.util.HashMap;
    导入java.util.HashSet;
    导入java.util.Iterator;
    导入java.util.List;
    导入java.util.Map;
    导入java.util.Set;
    公共类有序集{
    私有最终列表=新的ArrayList();
    私有最终集值=新HashSet();
    /**
    *如果不是dup,则插入值。
    *@如果实际插入了“值”(不是dup),则返回true。
    */
    公共布尔put(字符串值){
    if(值.包含(值))
    返回false;
    增加(价值);
    列表。添加(值);
    返回true;
    }
    公共布尔包含(字符串)
    
    package p1;
    
    import java.util.AbstractList;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    public class OrderedSet {
      private final List<String> list = new ArrayList<>();
      private final Set<String> values = new HashSet<>();
    
      /**
       * Inserts a value if it is not a dup.
       * @return true if "value" was actually inserted (not a dup).
       */
      public boolean put(String value) {
        if (values.contains(value)) 
          return false;
    
        values.add(value);
        list.add(value);
        return true;
      }
    
      public boolean contains(String string) {
        return values.contains(string);
      }
    
      public Iterator<String> iterator() {
        return list.iterator();
      }
    
      public int size() { return list.size(); }
    
      public List<String> subList(int begin, int end) {
        return new MyList(begin, end);
      }
    
      private class MyList extends AbstractList<String> {
        private final int begin;
        private final int end;
    
        public MyList(int begin, int end) {
          this.begin = begin;
          this.end = end;
        }
    
        @Override public String get(int index) {
          return list.get(begin + index);
        }
    
        @Override public int size() { 
          return end - begin;
        }
      }
    }
    
    package p1;
    
    import static org.junit.Assert.*;
    
    import java.util.Iterator;
    import java.util.List;
    
    import org.junit.Test;
    
    public class OrderedSetTest {
    
      @Test
      public void test() {
        OrderedSet om = new OrderedSet();
        assertTrue(om.put("a"));
        assertEquals(1, om.size());
        assertTrue(om.put("b"));
        om.put("c");
        assertEquals(3, om.size());
        assertFalse(om.put("a"));
        assertEquals(3, om.size());
        om.put("d");
        assertEquals(4, om.size());
        om.put("d");
        assertEquals(4, om.size());
        om.put("e");
        assertEquals(5, om.size());
    
    
        assertTrue(om.contains("a"));
        assertTrue(om.contains("b"));
        assertTrue(om.contains("c"));
        assertTrue(om.contains("d"));
        assertTrue(om.contains("e"));
        assertFalse(om.contains("a_"));
        assertFalse(om.contains("b_"));
        assertFalse(om.contains("f"));
    
        Iterator<String> iter = om.iterator();
        assertTrue(iter.hasNext());
        assertEquals("a", iter.next());
        assertTrue(iter.hasNext());
        assertEquals("b", iter.next());
        assertTrue(iter.hasNext());
        assertEquals("c", iter.next());
        assertTrue(iter.hasNext());
        assertEquals("d", iter.next());
        assertTrue(iter.hasNext());
        assertEquals("e", iter.next());
        assertFalse(iter.hasNext());
    
        List<String> sub = om.subList(2,  4);
        assertArrayEquals(new String[] { "c",  "d" }, sub.toArray(new String[0]));
      }
    }