循环或排序分层绘制?

时间:2009-08-17 19:33:16

标签: algorithm sorting loops

假设一个对象集合,每个对象都需要在特定的图层绘制,在什么时候(或曾经)更好地按层对每个对象进行排序而不是循环多次并在每次传递时绘制一个图层?更重要的是,你将如何得出这个结论?您要排序的排序算法的加分点?

for (obj = each in collection) {
  for (i=0; i<=topLayer; i++) {
    if (obj.layer == i) {
      obj.draw()
    }
  }
}

/* vs. */

function layerCompare(obj1, obj2) {
  return (obj1.layer > obj2.layer)
}

collection.sort(layerCompare) 

for (obj = each in collection) {
    obj.draw()
}

6 个答案:

答案 0 :(得分:3)

如果遍历每一层和每个对象,即O(m * n),其中m是层数,n是对象数。但是,如果您使用quicksort之类的方式提前对图层进行排序,则可以在O(n*log(n))中对它们进行排序,然后在O(n)中绘制它们,从而产生O(n*log(n) + n) = O(n*log(n))的总复杂度。

所以从理论上讲,总是更好地对它们进行排序。在实践中,您必须进行基准测试。

编辑:第二次检查时,截止值是m < log(n)。如果图层数小于对象数的对数,则应该进行双循环,否则对它们进行排序。

答案 1 :(得分:3)

如果您的代码不是很多层来来去去,那么始终保持图层排序更有意义。实现这一目标的一种方法是使图层本身成为可以包含对象的可绘制对象。此时,您的分层内置于图层对象本身的递归性质中。

或者,你可以只有一个图层列表,每个图层都是一个对象列表。

答案 2 :(得分:2)

我会为每个图层维护一个单独的集合(并且没有将图层作为每个对象的属性),这使得问题没有实际意义。将对象重新分配给不同的层(使用添加和删除)只会(大致)改变对象的图层属性的两倍,并且您将完全避免一次或一堆迭代的成本来获得每层中的对象。

答案 3 :(得分:1)

最大的问题是你的聪明才智。项目添加/删除/更改图层的频率如何?插入和冒泡排序(通常被认为表现不佳)对于几乎排序的数据非常有效。

另一个问题是你通过排序节省了多少工作?您的渲染功能适用于少量图层,但是您拥有的图层越多,效果越差。从复杂性的角度来看,您需要考虑层数和项目数,以及可能的每层分布。

如果你有一个很小的(当然是相对较小的)层数,那么为每个层设置一个单独的集合(可能是链表)可能是有意义的,并在它发生变化时将其移动到适当的层。

答案 4 :(得分:1)

如果图层数是固定的,则可以使用Pigeonhole sort这是一种O(n)算法。例如,如果有256个编号为0到255的图层,则创建一个大小为256的数组List<Obj>[] a,然后对于集合中的每个对象obj,执行a[obj.layer].add(obj)。最后,迭代遍历您的数组并绘制您的对象(如果0回来,for (int i = 0; i < a.length; i++) {for (Obj obj : a[i]) {draw(obj);}}

但我同意维护这些列表总是比重新生成它们更好。最简单的方法是将对象存储在按层排序的集合数据结构中,该结构允许按顺序迭代(例如,Java中的TreeSet)。

答案 5 :(得分:1)

如果你有 N 个对象和 L 层,那么循环的成本是 N 绘制 C <的成本sub> draw N×L 测试图层 C draw 的成本。

C test and paint =(C draw + C test ×L)×N

添加项目的成本是集合的插入成本;在层之间移动对象的成本可以忽略不计。

在大多数情况下,绘图成本将远远大于测试成本,( C draw &gt;&gt; C test )所以它取决于层数,无论 L×N 项是否具有明显的效果( C draw ÷C test < / sub> &gt;?L)。

排序意味着您有大约两个测试和 N ln 2 N 的插入;在第一近似中,这将花费大约3×C test N ln 2 N 。除非添加或删除对象或更改其图层,否则不需要重新排序,因此绘制成本通常只有线性成本。 (使用成本估算而不是试图划分不同的 O 值的原因是它给出了比例而不是增长 - O(LN)之间的切断 O(N ln N)不是 L == ln N ,因为 O 可能有一个大的常数项;你我必须自己衡量它的真实价值,而不是我所做的猜测。

C 排序和重绘 =(C draw + 3×C test ×ln 2 N)×N

C 仅绘画 = C draw ×N

但是,从软件设计的角度来看,我总是倾向于让每个图层在编辑时都有自己的成员集合 - 它可以更好地封装图层上的操作(显示图层,隐藏图层,仅从一个图层中选择,将图层移到顶部等)。

对于相当复杂的图形,除非可能的图层数量很大,否则任何一种方法都会快速相同,因为绘图的成本将是最大的术语。如果需要 1024×C test 来绘制 32×32 像素对象,那么需要超过100层C test和paint C 慢10%。为自己测量时间。