繁体   English   中英

维护具有性能的排序列表

[英]Maintain a sorted list with performance

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

我正在编写一个游戏,其中有很多“碰撞区”,每一帧都会检查。 为了优化,我有一个关于它们的排序的想法取决于它们的X位置。 问题不是所有碰撞区域都是静态的,因为它们中的一些可以移动。

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

所以我有了一个新想法:我可以使用一个树,每当一个区域的X被更改,而不是再次排序所有元素,我可以删除然后从树重新添加它。 但是,我认为在TreeList中添加和删除运算符也很昂贵。 而且,迭代Tree不如ConcurrentLinkedQueueLinkedListArrayList

请告诉我是否有任何内置数据结构满足我的需要。 如果没有这样的数据结构,我打算扩展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;
}

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

看来你正在进行插入排序,即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);

您可以通过将所有对象定义为不同来允许“重复”是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.
      }
   }
}

正如你所看到的,这种方法很难看,除非你有办法让每个对象都独一无二。

听起来你想要一个TreeSet

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

因此,我建议您执行测试提供的树实现(即TreeSet ),而不仅仅是猜测。 因为它们不是普通的树实现,所以如果迭代对它们来说也很快就不会感到惊讶。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM