我一直在努力寻找一种能够:
的数据结构我发现最接近的是LinkedHashSet
,但是由于没有实现List
界面并允许我在其上调用List
函数(例如{{} 1}})。有没有理由我找不到这样的结构?我即将实现我自己的subList
版本,但使用的是LinkedHashSet
(与Linked-list-backed ArrayList
相反)。我还从LinkedHashSet
库中找到了OrderedHashSet
,但由于没有实现所需的subList函数,这也不足......所以我真的很困惑为什么不需要它?或者我只是没想到要搜索的正确名称?
编辑2:抱歉抱歉,我应该更清楚我的第一个要求,我真的只需要真正有效地检查重复项。对我来说已经很晚了。
答案 0 :(得分:4)
基本上,您所发现的是提供O(1)点查找但提供有效范围扫描(迭代)的东西。在数据库领域,这种事情有时被称为clustered-index,其中数据使用一些查找结构组织,例如B-Tree或hash index,但叶子节点或条目index按某种特定顺序排序(在您的情况下,它按插入顺序排序)。下面显示了一个群集B树的示例,其中@Itay Maman的解决方案是群集哈希索引的一个示例。
在Java中,没有这样的类本身满足您的需求,可能是因为它的复杂性 - 很难(或几乎不可能)有一个这样的实现最适合所有工作负载(例如您发出的频率)范围扫描,您发出点查找的频率,是否允许多读者和多个编写者?等等)但是,这里有一些可能的解决方案,取决于您的用例。
如果在大多数情况下你并不真正关心第3项,那么使用LinkedHashMap,并使用LinkedHashMap提供的常规迭代来完成第3项。
如果您关心所有项目的性能并且您从不发出删除/更新,那么最简单的方法可能是使用HashMap和ArrayList一起将数据表示为聚簇索引。每个插入都是对HashMap的插入+附加到ArrayList,而HashMap的值是ArrayList的索引。这样可以提供最佳的读取性能,但是如果有的话,则需要解决更新/删除问题,可能是将ArrayList替换为子阵列的链接列表。
在极端情况下,你确实有删除/更新,想要支持多线程访问,甚至想要持久性,那么最好的方法是使用开源的嵌入式持久键值存储,如作为RocksDB或LevelDB,用于快速存储的嵌入式键值存储,如RAM或闪存(它也适用于磁盘工作负载。)虽然它们都是用C ++实现的,但它们确实有Java绑定(例如,Java中的RocksDB的简介page。)
当然,如果你可以重新实现某些东西,那么定制的LinkedHashMap可能是最简单的。只需添加迭代器的不同构造函数,它允许您在使用O(1)哈希定位的任何特定条目处开始迭代。
答案 1 :(得分:1)
修改
根据更新问题,您只需要一个不重复的集合(而不是键值映射)。这简化了一些事情。基本上,此解决方案使用: - 用于确定重复的(散列)集 - 一个简单的(数组)列表来维护插入顺序
除此之外,还有我们用于子列表的列表的自定义实现。我必须推出自己的(并且不依赖于ArrayList.subList()
),因为从ArrayList
返回的(子)列表不允许数组列表在创建后更改其大小。幸运的是,在AbstractList
的帮助下,这很简单(只需要两种方法来覆盖)。
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]));
}
}
答案 2 :(得分:0)
java.util.TreeSet会有帮助吗?
它不是O(1)(参考您的列表要求,第1点),但支持自然排序(第2点)和子集操作(第3点)。
答案 3 :(得分:-1)
数据结构不可能同时提供这些内容,它们是矛盾的:如果在O(1)时间内插入和访问元素,则意味着它们是随机分布的(带有哈希码),并且如果您想保留订单,那么插入和访问将花费您更多时间。 我相信你所寻找的是HashSet,而不是HashMap。这取决于插入的顺序对于项目的未来是否至关重要,您可以使用HashSet(快速,随机访问和插入),也可以使用ArrayList(较慢,但保持顺序)。 我认为您不可能创建满足您需求的数据结构。