维护具有性能的排序列表

时间:2012-12-22 10:44:54

标签: java android algorithm list data-structures

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

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

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

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

3 个答案:

答案 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),而不仅仅是猜测。因为它们不是普通的树实现,所以如果迭代也很快就会让我感到惊讶。