在Computational Geometry: Algorithms and Applications by Mark de Berg中,您可以找到以下binary space partitioning算法:
BSP(Finite set of finite non-intersecting line segments S)
{
if (n > 1)
{
Use the extension of the first segment in S as the splitting line L
Let S+ and S- be the set of fragments above and below L, respectively
Create a tree T with left subtree = BSP(S-) and right subtree BSP(S+)
Store all segments which overlap with L in T
}
else
Create a tree T and store S in T
return T
}
如果分割线L将片段切割成两半,则生成片段。您可以查看another question of me where I give an example for this process。
We can show BSP
生成的预期片段数最多为n + 2n log(n)
,如果这些片段是随机混洗的(这些片段的每个可能的排列具有相同的出现概率) )和n
表示段数。
我们如何约束预期的递归调用次数?
在 de Berg 一书中,作者指出预期的递归调用数量受预期生成片段数量的限制。 为什么
显然,一条拆分线L
最多可生成n - 1
个新碎片。在最坏的情况下,所有这些新片段都位于L
的一侧。在这种情况下,S+
和S-
中的每一个都包含n - 1
个元素。因此,我们将有两个输入大小为n - 1
的递归调用。这导致T(n) = n - 1 + 2 * T(n - 1)
的递归运行时间。 [n - 1
导致我们需要测试的元素数量是否高于或低于L
]。
我们可以展开递归,但我认为这将产生非常糟糕的估计。那么,我们该怎么做呢?我们如何利用已知的预期生成片段数?
答案 0 :(得分:0)
使用S非空的BSP调用与生成的片段一一对应。每次调用最多使用S empty进行一次递归调用,这不会产生递归调用,因此调用的总数受到生成的片段数量的两倍的限制。因此,这一陈述符合预期。
答案 1 :(得分:0)
“我们如何限制预期的递归调用次数?”:你不能。算法描述解释了这个预期的数字受到预期的片段数量的限制,你无法直接控制它们。
当段足够随机时,该数字是O(N Log(N)),这很好。但对于其他发行版,它可能更高甚至更低。
此外,您还担心最坏的情况,其复杂性可能是灾难性的(如O(N²))。
为了避免这种情况,您应该开发启发式算法来执行行L的选择,使得拆分是平衡的并且不会生成太多碎片。但你不能完全避免最坏的情况,只是极不可能。
这种情况提醒快速排序,具有O(N Log(N))预期行为,但O(N²)最坏情况。后者通过使用“三个中值”启发式来选择枢轴来驯服。
答案 2 :(得分:0)
我们证明,每次输入算法的主体时,都会消耗一个片段:
var message = MyUnsafeObjectAccess.Foobar;
Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show(message)); // safe
为空的情况,因为这可能会在算法中被“黑客攻击”,从而避免递归调用S
的第一个元素,导致它被选为分割线S
(并且不会发生进一步的递归调用);事实上,l
与S
重叠的所有元素都被消耗了(但同样,这与我们无关,因为我们对最坏情况的约束感兴趣)因此,递归调用的数量受生成的片段数量的限制。由于预期生成的片段数为l
,因此预期的递归调用次数也为O(n ln n)
。