Java 访问SortedSet中特定元素的最有效方式是什么?
我想使用一个已排序的集合,但我可以通过索引访问其中的元素,也就是说,我想要同时具有集合和列表特征的集合。Java.util.TreeSet非常接近我的需要,但不允许通过索引进行访问 我可以想出几个选择:Java 访问SortedSet中特定元素的最有效方式是什么?,java,list,performance,set,Java,List,Performance,Set,我想使用一个已排序的集合,但我可以通过索引访问其中的元素,也就是说,我想要同时具有集合和列表特征的集合。Java.util.TreeSet非常接近我的需要,但不允许通过索引进行访问 我可以想出几个选择: 每当我需要一个特定的元素时,我都可以遍历树集 当我需要访问特定元素时,我可以维护一个树集并从中生成一个列表 如上所述,仅缓存列表,直到集合发生更改 我可以有一个列表,并在需要添加元素时自行排序 等等 在各种选择之间有各种权衡。我希望有人能给我一些好的建议。要回答关于“为什么要这样做?”的潜在问题
在各种选择之间有各种权衡。我希望有人能给我一些好的建议。要回答关于“为什么要这样做?”的潜在问题,请阅读算法。也许Treeset和apache commons collections API的组合可以解决您的问题以下几点:
- 这算不上答案,但当我上次需要重新实现一个频繁项集挖掘算法时,我选择了FP-growth,它的性能与先验算法相当(或更好),在我看来,更容易实现。这项技术是由Jiawei Han和其他人开发的,基本上在数据挖掘中有一个专门的章节:概念和技术
- 有几种开源工具采用相当标准化的输入(每行一个整数列表;整数表示项,行表示项集)。它们中的一些让你可以选择算法。这里提供了许多许可证:
- 请记住,仅使用任何
实现并不能获得列表
元素访问,除非您专门使用数组/向量。更有可能的是,您将从保留大部分或完全排序的数组中获得更好的收益(使用二进制搜索查找超过特定限制的元素,并使用常规索引进行随机访问)O(1)
- 我会调查。它维护哈希集的插入顺序。
我也有同样的问题。因此,我获取了java.util.TreeMap的源代码并编写了IndexedTreeMap。它实现了我自己的索引导航地图:
public interface IndexedNavigableMap<K, V> extends NavigableMap<K, V> {
K exactKey(int index);
Entry<K, V> exactEntry(int index);
int keyIndex(K k);
}
public interface IndexedNavigableMap扩展了NavigableMap{
K精确键(int索引);
条目精确条目(int索引);
int键索引(K);
}
该实现基于在红黑树发生更改时更新节点权重。权重是给定节点下的子节点数加上一个self。例如,当树向左旋转时:
private void rotateLeft(Entry<K, V> p) {
if (p != null) {
Entry<K, V> r = p.right;
int delta = getWeight(r.left) - getWeight(p.right);
p.right = r.left;
p.updateWeight(delta);
if (r.left != null) {
r.left.parent = p;
}
r.parent = p.parent;
if (p.parent == null) {
root = r;
} else if (p.parent.left == p) {
delta = getWeight(r) - getWeight(p.parent.left);
p.parent.left = r;
p.parent.updateWeight(delta);
} else {
delta = getWeight(r) - getWeight(p.parent.right);
p.parent.right = r;
p.parent.updateWeight(delta);
}
delta = getWeight(p) - getWeight(r.left);
r.left = p;
r.updateWeight(delta);
p.parent = r;
}
}
private void rotateLeft(条目p){
如果(p!=null){
条目r=右侧;
int delta=getWeight(左)-getWeight(右);
p、 右=右=左;
p、 更新视图(增量);
如果(右左!=null){
r、 left.parent=p;
}
r、 父母=父母;
如果(p.parent==null){
根=r;
}else if(p.parent.left==p){
delta=getWeight(r)-getWeight(p.parent.left);
p、 parent.left=r;
p、 parent.updatewight(delta);
}否则{
delta=getWeight(r)-getWeight(p.parent.right);
p、 parent.right=r;
p、 parent.updatewight(delta);
}
delta=重量(p)-重量(r.左);
r、 左=p;
r、 更新视图(增量);
p、 父代=r;
}
}
UpdateView只更新根目录下的权重:
void updateWeight(int delta) {
weight += delta;
Entry<K, V> p = parent;
while (p != null) {
p.weight += delta;
p = p.parent;
}
}
void updatewight(int delta){
重量+=增量;
条目p=父项;
while(p!=null){
p、 重量+=增量;
p=p.parent;
}
}
当我们需要通过索引查找元素时,这里是使用权重的实现:
public K exactKey(int index) {
if (index < 0 || index > size() - 1) {
throw new ArrayIndexOutOfBoundsException();
}
return getExactKey(root, index);
}
private K getExactKey(Entry<K, V> e, int index) {
if (e.left == null && index == 0) {
return e.key;
}
if (e.left == null && e.right == null) {
return e.key;
}
if (e.left != null && e.left.weight > index) {
return getExactKey(e.left, index);
}
if (e.left != null && e.left.weight == index) {
return e.key;
}
return getExactKey(e.right, index - (e.left == null ? 0 : e.left.weight) - 1);
}
public K exactKey(int索引){
如果(索引<0 | |索引>大小()-1){
将新的ArrayIndexOutOfBoundsException()抛出;
}
返回getExactKey(根,索引);
}
私有K getExactKey(条目e,int索引){
if(e.left==null&&index==0){
返回e.key;
}
if(e.left==null&&e.right==null){
返回e.key;
}
if(e.left!=null&&e.left.weight>index){
返回getExactKey(如左,索引);
}
if(e.left!=null&&e.left.weight==index){
返回e.key;
}
返回getExactKey(e.right,index-(e.left==null?0:e.left.weight)-1);
}
查找键的索引也非常方便:
public int keyIndex(K key) {
if (key == null) {
throw new NullPointerException();
}
Entry<K, V> e = getEntry(key);
if (e == null) {
throw new NullPointerException();
}
if (e == root) {
return getWeight(e) - getWeight(e.right) - 1;//index to return
}
int index = 0;
int cmp;
index += getWeight(e.left);
Entry<K, V> p = e.parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {
while (p != null) {
cmp = cpr.compare(key, p.key);
if (cmp > 0) {
index += getWeight(p.left) + 1;
}
p = p.parent;
}
} else {
Comparable<? super K> k = (Comparable<? super K>) key;
while (p != null) {
if (k.compareTo(p.key) > 0) {
index += getWeight(p.left) + 1;
}
p = p.parent;
}
}
return index;
}
public int-keyIndex(K键){
if(key==null){
抛出新的NullPointerException();
}
条目e=获取条目(键);
如果(e==null){
抛出新的NullPointerException();
}
if(e==根){
return getWeight(e)-getWeight(e.right)-1;//要返回的索引
}
int指数=0;
int-cmp;
索引+=获取权重(如左);
条目p=e.parent;
//拆分比较器和可比较路径
Comparator可能会让您对算法和实现指针感兴趣这与我的需求不太相符。Apriori看起来相对简单,可能对我的任务来说效率足够高。我对FP增长不太熟悉。我来看看。谢谢!(+1)KC2001:不客气。“更容易实施”可能是相当主观的,它们可能是标准的。FP增长更有趣一些,而且肯定更接近最先进的。