经典排序算法 - 合并两个有序的数组

部署运行你感兴趣的模型镜像

1.问题描述:

给定两个排序后的数组A和B,其中A的末端有足够的缓冲空间容纳B。编写一个方法,将B 合并入A并排序。

2. 解题思路:

可以通过从后向前合并的方式解决,因为数组A末端有足够的缓冲空间

3. 图解流程:

使用多张图,演示下面代码的整个流程:

1)初始状态图:

数组A: [1, 3, 5, 0, 0, 0] (m=3)
数组B: [2, 4, 6] (n=3)
指针位置:
i=2 (指向A的5)
j=2 (指向B的6)
k=5 (指向A最后一个0)

2)第一轮比较 (A[2]=5 vs B[2]=6):

6 > 5 → 将6放入A[5]
数组A: [1, 3, 5, 0, 0, 6]
指针移动: j--=1, k--=4

3)第二轮比较 (A[2]=5 vs B[1]=4):

5 > 4 → 将5放入A[4]
数组A: [1, 3, 5, 0, 5, 6]
指针移动: i--=1, k--=3

4)第三轮比较 (A[1]=3 vs B[1]=4):

4 > 3 → 将4放入A[3]
数组A: [1, 3, 5, 4, 5, 6]
指针移动: j--=0, k--=2

5)第四轮比较 (A[1]=3 vs B[0]=2):

3 > 2 → 将3放入A[2]
数组A: [1, 3, 3, 4, 5, 6]
指针移动: i--=0, k--=1

6)第五轮比较 (A[0]=1 vs B[0]=2):

2 > 1 → 将2放入A[1]
数组A: [1, 2, 3, 4, 5, 6]
指针移动: j--=-1, k--=0

7)结束状态:

j=-1 (B已处理完)
最终数组A: [1, 2, 3, 4, 5, 6]

这个流程展示了如何从后向前合并两个已排序数组,避免了元素覆盖问题,且不需要额外空间。每个步骤都通过比较两个数组当前元素,将较大的放入目标位置,直到所有元素处理完毕。

4.代码实现

核心逻辑

  • 指针初始化i 指向数组 A 的最后一个有效元素,j 指向数组 B 的末尾,k 指向合并后的末尾。
  • 从后向前合并:比较 A[i]B[j],较大者放入 A[k] 并移动对应指针。
  • 处理剩余元素:如果 B 中有剩余元素,直接复制到 A 中。

语言特性

  • PHP 数组自动扩展;使用 array_pad 扩展数组 A 的空间,使其能容纳合并后的所有元素。
  • Go:使用切片操作,直接修改传入的切片。
  • Java:数组长度固定,需提前预留空间。
  • Python:动态扩展列表长度(如 A = [1,3,5] + [0]*3)。

php版本:

function mergeSortedArrays(&$A, $m, $B, $n) {
    $i = $m - 1;    // A 的有效元素末尾指针
    $j = $n - 1;    // B 的末尾指针
    $k = $m + $n - 1; // 合并后的数组末尾指针

    // 从后向前合并
    while ($i >= 0 && $j >= 0) {
        if ($A[$i] > $B[$j]) {
            $A[$k--] = $A[$i--];
        } else {
            $A[$k--] = $B[$j--];
        }
    }

    // 处理 B 中剩余元素
    while ($j >= 0) {
        $A[$k--] = $B[$j--];
    }
}

// 示例测试
$A = [1, 3, 5];        // 初始有效元素 [1, 3, 5]
$B = [2, 4, 6];
$A = array_pad($A, count($A) + count($B), 0); // 扩展空间

mergeSortedArrays($A, 3, $B, 3);
echo implode(" ", $A);  // 输出:1 2 3 4 5 6

python 版本:

def merge_sorted_arrays(A, m, B, n):
    i = m - 1  # A的最后一个有效元素索引
    j = n - 1  # B的最后一个元素索引
    k = m + n - 1  # 合并后的末尾索引

    # 从后向前合并,直到A或B处理完毕
    while i >= 0 and j >= 0:
        if A[i] > B[j]:
            A[k] = A[i]
            i -= 1
        else:
            A[k] = B[j]
            j -= 1
        k -= 1

    # 处理B中剩余的元素(若存在)
    while j >= 0:
        A[k] = B[j]
        j -= 1
        k -= 1


if __name__ == "__main__":
    A = [1, 3, 5] + [0] * 3  # 扩展空间
    B = [2, 4, 6]
    merge_sorted_arrays(A, 3, B, 3)
    print(A)  # 输出 [1, 2, 3, 4, 5, 6]

golang版本:

package main
import "fmt"

func mergeSortedArrays(A []int, m int, B []int, n int) {
    i, j, k := m-1, n-1, m+n-1
    for i >= 0 && j >= 0 {
        if A[i] > B[j] {
            A[k] = A[i]
            i--
        } else {
            A[k] = B[j]
            j--
        }
        k--
    }
    // 处理 B 剩余元素
    for j >= 0 {
        A[k] = B[j]
        j--
        k--
    }
}

func main() {
    A := []int{1, 3, 5, 0, 0, 0}  // 后三个0为预留空间
    B := []int{2, 4, 6}
    mergeSortedArrays(A, 3, B, 3)
    fmt.Println(A)  // 输出 [1 2 3 4 5 6]
}

java 版本:

public class Main {
    public static void mergeSortedArrays(int[] A, int m, int[] B, int n) {
        int i = m - 1, j = n - 1, k = m + n - 1;
        while (i >= 0 && j >= 0) {
            if (A[i] > B[j]) {
                A[k--] = A[i--];
            } else {
                A[k--] = B[j--];
            }
        }
        // 处理 B 剩余元素
        while (j >= 0) {
            A[k--] = B[j--];
        }
    }

    public static void main(String[] args) {
        int[] A = {1, 3, 5, 0, 0, 0}; // 后三个0为预留空间
        int[] B = {2, 4, 6};
        mergeSortedArrays(A, 3, B, 3);
        for (int num : A) {
            System.out.print(num + " "); // 输出 1 2 3 4 5 6
        }
    }
}

5.复杂度分析

  • 时间复杂度:O(m + n),遍历两个数组各一次。
  • 空间复杂度:O(1),原地操作,无需额外空间。

6.边界测试

  1. B 全部小于 A
    A = [4,5,6] + [0]*3
    B = [1,2,3]
    merge_sorted_arrays(A, 3, B, 3)
    print(A) # 输出 [1,2,3,4,5,6]
  2. A 或 B 为空
    A := []int{0, 0, 0}
    B := []int{1, 2, 3}
    mergeSortedArrays(A, 0, B, 3)  // A为空
    fmt.Println(A)  // 输出 [1,2,3]

您可能感兴趣的与本文相关的镜像

Python3.9

Python3.9

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值