排序算法之:最小交换次数排序(Minimum Swaps to Sort)的图论模型与环分解优化
字数 1332 2025-11-30 06:17:20

排序算法之:最小交换次数排序(Minimum Swaps to Sort)的图论模型与环分解优化

题目描述
给定一个包含 n 个不同整数的数组 arr,数组中的元素是 0n-1 的任意排列。要求通过交换任意两个元素的位置,将数组升序排列,求所需的最小交换次数。例如:
输入:arr = [4, 3, 2, 1, 0]
输出:2(交换过程可能为:交换索引0和4→[0,3,2,1,4],再交换索引1和3→[0,1,2,3,4])。


解题过程

1. 问题分析

  • 直接通过排序算法(如快速排序)只能得到排序结果,但无法记录最小交换次数。
  • 关键观察:若元素已排序,则元素 i 应位于索引 i 处。交换操作的本质是将元素移动到其正确位置。
  • 目标:通过最少的交换次数,使每个元素回到其目标位置(即 arr[i] = i)。

2. 图论建模

  • 将数组视为一个置换(Permutation),并构建一个有向图:

    • 节点:数组的索引 0n-1
    • 边:从节点 i 指向节点 arr[i](表示当前位于 i 的元素应去往位置 arr[i])。
  • 例如 arr = [4, 3, 2, 1, 0] 的边为:
    0→4, 1→3, 2→2, 3→1, 4→0

  • 性质:由于每个节点出度和入度均为1,图由若干不相交的环组成。

    • 自环(如 2→2)表示元素已在正确位置,无需交换。
    • 每个长度为 k 的环需要 k-1 次交换才能将环内所有元素归位。

3. 最小交换次数公式

  • 设图中有 c 个环(包括自环),每个环的长度为 l₁, l₂, ..., l_c
  • 总交换次数 = (l₁ - 1) + (l₂ - 1) + ... + (l_c - 1) = n - c
  • 推导:每次交换可减少一个环(例如交换环中两个元素可将环拆分为两个),最终需要 n 个自环,而初始有 c 个环,故需 n - c 次交换。

4. 算法步骤

  1. 遍历数组,构建并检测环的数量:
    • visited 数组标记已访问的索引。
    • 从索引 i 开始,沿边 i → arr[i] 遍历,直到回到起点,记录一个环。
  2. 统计所有环的数量 c(包括自环)。
  3. 返回 n - c

示例计算
arr = [4, 3, 2, 1, 0]

  • 环1: 0 → 4 → 0(长度2)
  • 环2: 1 → 3 → 1(长度2)
  • 环3: 2 → 2(自环,长度1)
    环数 c = 3,交换次数 = 5 - 3 = 2

5. 代码实现(Python)

def min_swaps(arr):
    n = len(arr)
    visited = [False] * n
    cycles = 0
    
    for i in range(n):
        if not visited[i] and arr[i] != i:
            cycles += 1
            current = i
            while not visited[current]:
                visited[current] = True
                current = arr[current]  # 移动到下一个节点
    
    return n - cycles

# 测试
arr = [4, 3, 2, 1, 0]
print(min_swaps(arr))  # 输出 2

6. 复杂度分析

  • 时间复杂度:O(n),每个节点仅被访问一次。
  • 空间复杂度:O(n),用于记录访问状态。

7. 扩展:处理重复元素
若数组包含重复元素,上述方法失效(因置换图模型要求元素唯一)。此时需改用其他策略,如转化为最小交换次数使相邻元素有序问题(较复杂,需另讨论)。

总结
通过将置换分解为环,最小交换次数问题被转化为图论中的环计数问题,利用 n - c 公式高效求解。该方法高效且直观,体现了排序问题与图论的深刻联系。

排序算法之:最小交换次数排序(Minimum Swaps to Sort)的图论模型与环分解优化 题目描述 给定一个包含 n 个不同整数的数组 arr ,数组中的元素是 0 到 n-1 的任意排列。要求通过交换任意两个元素的位置,将数组升序排列,求所需的最小交换次数。例如: 输入: arr = [4, 3, 2, 1, 0] 输出: 2 (交换过程可能为:交换索引0和4→[ 0,3,2,1,4],再交换索引1和3→[ 0,1,2,3,4 ])。 解题过程 1. 问题分析 直接通过排序算法(如快速排序)只能得到排序结果,但无法记录最小交换次数。 关键观察:若元素已排序,则元素 i 应位于索引 i 处。交换操作的本质是将元素移动到其正确位置。 目标:通过最少的交换次数,使每个元素回到其目标位置(即 arr[i] = i )。 2. 图论建模 将数组视为一个 置换(Permutation) ,并构建一个有向图: 节点:数组的索引 0 到 n-1 。 边:从节点 i 指向节点 arr[i] (表示当前位于 i 的元素应去往位置 arr[i] )。 例如 arr = [4, 3, 2, 1, 0] 的边为: 0→4, 1→3, 2→2, 3→1, 4→0 。 性质:由于每个节点出度和入度均为1,图由若干不相交的环组成。 自环(如 2→2 )表示元素已在正确位置,无需交换。 每个长度为 k 的环需要 k-1 次交换才能将环内所有元素归位。 3. 最小交换次数公式 设图中有 c 个环(包括自环),每个环的长度为 l₁, l₂, ..., l_c 。 总交换次数 = (l₁ - 1) + (l₂ - 1) + ... + (l_c - 1) = n - c 。 推导:每次交换可减少一个环(例如交换环中两个元素可将环拆分为两个),最终需要 n 个自环,而初始有 c 个环,故需 n - c 次交换。 4. 算法步骤 遍历数组,构建并检测环的数量: 用 visited 数组标记已访问的索引。 从索引 i 开始,沿边 i → arr[i] 遍历,直到回到起点,记录一个环。 统计所有环的数量 c (包括自环)。 返回 n - c 。 示例计算 arr = [4, 3, 2, 1, 0] : 环1: 0 → 4 → 0 (长度2) 环2: 1 → 3 → 1 (长度2) 环3: 2 → 2 (自环,长度1) 环数 c = 3 ,交换次数 = 5 - 3 = 2 。 5. 代码实现(Python) 6. 复杂度分析 时间复杂度: O(n) ,每个节点仅被访问一次。 空间复杂度: O(n) ,用于记录访问状态。 7. 扩展:处理重复元素 若数组包含重复元素,上述方法失效(因置换图模型要求元素唯一)。此时需改用其他策略,如转化为 最小交换次数使相邻元素有序 问题(较复杂,需另讨论)。 总结 通过将置换分解为环,最小交换次数问题被转化为图论中的环计数问题,利用 n - c 公式高效求解。该方法高效且直观,体现了排序问题与图论的深刻联系。