我的问题摘要:我需要一个可以快速迭代和排序的列表(通过排序方法或添加/删除对象)。
我正在编写一个游戏,其中有很多“碰撞区”,每一帧都会检查一次。为了优化,我有一个关于它们的排序的想法取决于它们的X位置。问题不是所有碰撞区域都是静态的,因为它们中的一些可以四处移动。
我已设法处理所有更改,但维护使用ArrayList
排序的ConcurrentLinkedQueue
(或Collections.sort()
)速度太慢。
所以我有了一个新想法:我可以使用一个树,每当一个区域的X被更改,而不是再次排序所有元素,我可以删除然后从树重新添加它。但是,我认为在TreeList中添加和删除运算符也很昂贵。此外,迭代树不如ConcurrentLinkedQueue
,LinkedList
或ArrayList
有效。
请告诉我是否有满足我需要的内置数据结构。如果没有这样的数据结构,我打算扩展ArrayList
类,覆盖add
方法以确保顺序(通过使用重载add(index, item)
。如果您认为这是最好的方法,请给我最好的方法来找到索引。我已经使用了BinarySearch,但我认为有一个错误:
@Override
public boolean add(T e) {
// Find the position
int left = 0;
int right = this.size() - 1;
int pos = right / 2;
if (e.compareTo(this.get(0)) <= 0) {
pos = 0;
} else if (e.compareTo(this.get(this.size() - 1)) >= 0) {
pos = this.size();
} else {
// Need: e[pos - 1] <= e[pos] <= e[pos + 1]
boolean firstCondition = false;
boolean secondCondition = false;
do {
firstCondition = this.get(pos - 1).compareTo(this.get(pos)) <= 0;
secondCondition = this.get(pos).compareTo(this.get(pos + 1)) >= 0;
if (!firstCondition) {
right = pos - 1;
pos = (left + right) / 2;
} else if (!secondCondition) {
left = pos + 1;
pos = (left + right) / 2;
}
} while (!(firstCondition && secondCondition));
}
this.add(pos, e);
return true;
}
答案 0 :(得分:1)
我会使用树集。如果需要允许重复,可以使用自定义比较器。迭代树集比数组略慢,添加和删除要快得多。
看来你正在进行插入排序,即O(n)。树集上的插入是O(ln n)
恕我直言通过使用TreeMap<MyKey, List<MyType>>
这样的
Map<MyKey, List<MyType>> map = new TreeMap<>();
// to add
MyType type = ...
MyKey key = ...
List<MyType> myTypes = map.get(key);
if (myTypes == null)
map.put(key, myTypes = new ArrayList<>());
myTypes.add(type);
// to remove
MyType type = ...
MyKey key = ...
List<MyType> myTypes = map.get(key);
if (myTypes != null) {
myTypes.remove(myType);
if (myTypes.isEmpty())
map.remove(key);
}
在这种情况下,添加和删除是O(ln N);
您可以通过将所有对象定义为不同的对象来允许“duplicates”是TreeSet。
Set<MyType> set = new TreeSet<>(new Comparator<MyType>() {
public int compare(MyType o1, MyType o2) {
int cmp = /* compare the normal way */
if (cmp == 0) {
// or use System.identityHashCode()
cmp = Integer.compare(o1.hashCode(), o2.hashCode());
return cmp == 0 ? 1 : cmp; // returning 0 is a bad idea.
}
}
}
正如你所看到的,这种方法很难看,除非你有办法让每个对象都独一无二。
答案 1 :(得分:0)
听起来你想要TreeSet。
答案 2 :(得分:0)
如果您打算在已排序的数组或ArrayList上使用二进制搜索/插入,那么您将获得与二叉树相同的大O复杂度。
所以我建议您实现 test 提供的树实现(即TreeSet
),而不仅仅是猜测。因为它们不是普通的树实现,所以如果迭代也很快就会让我感到惊讶。