【问题标题】:Algorithm that sorts a permutation排序排列的算法
【发布时间】:2015-04-04 08:41:42
【问题描述】:

我被这个问题困住了:


给定 {0,1,2,...,n-1} 的排列 P
(这里 n = P . 长度)

解释为什么以下算法按升序对排列进行排序并给出最坏的情况(伪代码)

PermutationSort(P)
    for i = 0 to P.length - 1
        while(P[i] != i)
            t = P[i]
            exchange P[i] with P[t]

(C++代码)

void PermutationSort(int P[], int len)
{
    for(int i = 0; i < len; i++)
        while(P[i] != i)
        {
            int tmp;
            tmp = P[i];
            P[i] = P[tmp];
            P[tmp] = tmp;
        }
}

我完全不知道为什么它对排列 P 进行排序。

我整天都在研究这个问题,但我仍然不明白为什么它会对排列进行排序。

“用 P[P[i]] 交换 P[i]”是做什么的,为什么我们最终会得到 P[i] = i 从而终止内部循环?

感谢任何提示或帮助。

【问题讨论】:

  • 大小为 N 的排列(当然)是0,1,2,...,N-1,N。 IE。如果已排序,则数组索引[i] 保存整数值i。 ...
  • 提示:每个排列都可以分解为不相交的cycles。考虑一下你的内部循环对包含iP[i] 的循环做了什么。
  • @IlmariKaronen 非常感谢您的提示。我研究了互联网并阅读了一些论文,现在我(几乎)理解了它。它实际上类似于“循环”排序。

标签: c++ algorithm sorting permutation


【解决方案1】:

首先,请注意,如果您从任意元素k开始,并重复应用排列P以获得类似(kP(k) → P(P(k)) → P(P(P(k))) → ...),你会(因为总P 排列中的元素数量是有限的,并且排列永远不会将两个输入映射到相同的输出)最终回到 kcycle 的元素 (k →P(k) → P(P(k )) → ... → k) 被称为 Pkorbit,并且排列恰好属于这样一个循环。

现在,让我们看看你的算法的内部循环对包含元素 i 的循环做了什么。

如果 P(i ) = ​​i,即如果这个元素已经在它所属的位置,那么内部循环什么也不做,并且外循环移动到下一个元素。但是,如果 P(i ) ≠ i,则内部循环设置 t = P em>(i ),然后将置换P修改为交换P(i )和 P(t ).

交换后,P(t )的新值是P(i)的旧值> ),即t。因此,元素 t 现在已正确排序,而 P(i ) 现在包含 P 的旧值(t ) = ​​P(P(i )),即循环中的(前)下一个元素.如果这是i,那么循环中没有元素了,内循环结束;否则,包含 i 的循环将缩小一个元素,并且内部循环重复。

因此,在内循环结束时,曾经与 i 属于同一循环的所有元素(包括 i 本身)都已移动到它们的正确位置,因此从循环中删除,而其余的排列没有改变。

由于外部循环遍历排列中的每个元素,因此也保证至少访问每个循环一次。当然,我们正在修改内部循环中的排列,但这没关系,因为内部循环永远不会创建新的循环(超过一个元素);它只能分解现有的。

因此,原始排列中的每个循环第一次被外循环访问时,内循环排序并分解该循环;在随后访问相同的原始循环时,该循环已经被排序,因此内部循环根本不做任何事情。

这个观察还应该允许您限制内部循环可以执行的次数,从而确定算法的时间复杂度。

【讨论】:

  • 非常感谢您的详细解释。
最近更新 更多