Java 维护具有性能的排序列表

Java 维护具有性能的排序列表,java,android,algorithm,list,data-structures,Java,Android,Algorithm,List,Data Structures,我的问题摘要:我需要一个可以快速迭代和排序的列表(通过排序方法或添加/删除对象) 我正在编写一个游戏,其中有很多“碰撞区”,每一帧都会被检查。对于优化,我有一个想法,根据它们的X位置对它们进行排序。问题是并非所有碰撞区域都是静态的,因为其中一些区域可以四处移动 我已设法处理所有更改,但要维护使用集合排序的ArrayList(或ConcurrentLinkedQueue),sort()太慢 所以我有了一个新的想法:我可以使用一棵树,每当一个区域的X发生变化,我就可以从树中删除然后重新添加它,而不是

我的问题摘要:我需要一个可以快速迭代和排序的列表(通过排序方法或添加/删除对象)

我正在编写一个游戏,其中有很多“碰撞区”,每一帧都会被检查。对于优化,我有一个想法,根据它们的X位置对它们进行排序。问题是并非所有碰撞区域都是静态的,因为其中一些区域可以四处移动

我已设法处理所有更改,但要维护使用集合排序的
ArrayList
(或
ConcurrentLinkedQueue
),sort()太慢

所以我有了一个新的想法:我可以使用一棵树,每当一个区域的X发生变化,我就可以从树中删除然后重新添加它,而不是再次对所有元素进行排序。然而,我认为在树列表中添加和删除操作符也很昂贵。此外,在树中迭代不如
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;
}
@覆盖
公共布尔加法(TE){
//找到位置
int左=0;
int right=this.size()-1;
int pos=右/2;
如果(e.compareTo(this.get(0))=0){
pos=这个.size();
}否则{

//需要:e[pos-1]听起来你想要一个。

如果你打算在已经排序的数组或数组列表上使用二进制搜索/插入,那么你将得到与二叉树相同的大O复杂度


因此,我建议您实际测试提供的树实现(即
TreeSet
),而不仅仅是猜测。由于它们不是简单的树实现,如果迭代速度也很快,我不会感到惊讶。

我会使用树集。如果需要允许重复,可以使用自定义比较器。虽然迭代树集比数组稍慢,但添加和删除要快得多

看起来您正在执行的插入排序是O(n)。树集上的插入排序是O(ln n)

我想通过使用
TreeMap
来存储副本的最佳方法是什么

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);
}
Map Map=newtreemap();
//加
MyType类型=。。。
MyKey=。。。
List myTypes=map.get(key);
if(myTypes==null)
put(key,myTypes=newarraylist());
添加(类型);
//除去
MyType类型=。。。
MyKey=。。。
List myTypes=map.get(key);
if(myTypes!=null){
myTypes.remove(myType);
if(myTypes.isEmpty())
地图。删除(键);
}
在这种情况下,添加和删除是O(lnn)

您可以通过将所有对象定义为不同的来允许“重复”是树集,例如

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.
      }
   }
}
Set Set=新树集(新比较器(){
公共整数比较(MyType o1,MyType o2){
int cmp=/*以正常方式进行比较*/
如果(cmp==0){
//或者使用System.identityHashCode()
cmp=Integer.compare(o1.hashCode(),o2.hashCode());
return cmp==0?1:cmp;//返回0是个坏主意。
}
}
}

正如您所看到的,除非您有某种方法使每个对象都是唯一的,否则这种方法是丑陋的。

我认为您不可能有两个碰撞,它们可以是
.equal()
?如果这样,请让您的碰撞对象实现equals()/hashCode()和Compariable有效并使用SortedSet。@fge否,比较器是使用X位置执行的,因此可能有许多碰撞区域具有相同的X位置。此外,SortedSet只是一个接口,其Java实现是
TreeSet
。我知道SortedSet是一个接口;)至于比较,你可以在多个x上进行比较,不是吗?@fge啊,我明白了,所以如果两个x位置相等,我就可以比较两个唯一的数字,比如hashCode,对吧?好吧,hashCode在定义上不是唯一的,所以我不会依赖于此……你能给我一个如何存储重复的例子吗?据我所知,树不能存储重复ed元素。在我的例子中,多个碰撞区域可以具有相同的X位置,因此它们满足“相等”条件。谢谢,我现在明白了。我可以使用静态ID号并为每个对象分配(然后增加)它。我认为在你的例子中,可以解决“罕见情况”当hashCodes相等时,只返回1是危险的?正确的,您可以使用像AtomicInteger.getAndIncrement()这样的唯一id。