微信登录

归并排序 - 算法实现 - 归并排序的代码实现

归并排序 - 算法实现 - 归并排序的代码实现

引言

在计算机科学的浩瀚海洋中,排序算法如同璀璨的明珠,各自散发着独特的光芒。而归并排序,以其稳定且高效的特性,在众多排序算法中占据着重要的一席之地。它就像是一位技艺精湛的指挥家,能将无序的元素序列有条不紊地排列整齐。本文将深入探讨归并排序的原理,并给出其代码实现,带领大家领略这一经典算法的魅力。

归并排序的原理

归并排序采用了分治法(Divide and Conquer)的思想,这一思想的核心就如同将一个复杂的大问题分解为多个简单的小问题,然后逐个击破,最后将小问题的解合并起来得到大问题的解。归并排序具体的执行步骤如下:

分解(Divide)

将待排序的数组从中间分成两个子数组,然后递归地对这两个子数组继续进行分解,直到每个子数组中只有一个元素或者为空。这就好比将一整副扑克牌不断地分成两堆,直到每堆只剩下一张牌。

解决(Conquer)

由于每个子数组都只有一个元素或者为空,它们本身已经是有序的。接下来,将这些有序的子数组合并成一个更大的有序数组。这就像是把已经整理好顺序的小牌堆合并成一个更大的有序牌堆。

合并(Merge)

合并的过程是归并排序的关键。比较两个子数组的元素,依次取出较小的元素放入一个新的数组中,直到两个子数组的元素都被取完。

代码实现

Python 实现

  1. def merge_sort(arr):
  2. # 如果数组长度小于等于 1,直接返回
  3. if len(arr) <= 1:
  4. return arr
  5. # 找到数组的中间位置
  6. mid = len(arr) // 2
  7. # 递归地对左半部分进行排序
  8. left_half = merge_sort(arr[:mid])
  9. # 递归地对右半部分进行排序
  10. right_half = merge_sort(arr[mid:])
  11. # 合并两个有序的子数组
  12. return merge(left_half, right_half)
  13. def merge(left, right):
  14. result = []
  15. i = j = 0
  16. # 比较两个子数组的元素,将较小的元素依次放入结果数组中
  17. while i < len(left) and j < len(right):
  18. if left[i] < right[j]:
  19. result.append(left[i])
  20. i += 1
  21. else:
  22. result.append(right[j])
  23. j += 1
  24. # 将左子数组中剩余的元素添加到结果数组中
  25. result.extend(left[i:])
  26. # 将右子数组中剩余的元素添加到结果数组中
  27. result.extend(right[j:])
  28. return result
  29. # 测试代码
  30. arr = [38, 27, 43, 3, 9, 82, 10]
  31. sorted_arr = merge_sort(arr)
  32. print("排序后的数组:", sorted_arr)

Java 实现

  1. import java.util.Arrays;
  2. public class MergeSort {
  3. public static int[] mergeSort(int[] arr) {
  4. if (arr.length <= 1) {
  5. return arr;
  6. }
  7. int mid = arr.length / 2;
  8. int[] left = Arrays.copyOfRange(arr, 0, mid);
  9. int[] right = Arrays.copyOfRange(arr, mid, arr.length);
  10. left = mergeSort(left);
  11. right = mergeSort(right);
  12. return merge(left, right);
  13. }
  14. public static int[] merge(int[] left, int[] right) {
  15. int[] result = new int[left.length + right.length];
  16. int i = 0, j = 0, k = 0;
  17. while (i < left.length && j < right.length) {
  18. if (left[i] < right[j]) {
  19. result[k++] = left[i++];
  20. } else {
  21. result[k++] = right[j++];
  22. }
  23. }
  24. while (i < left.length) {
  25. result[k++] = left[i++];
  26. }
  27. while (j < right.length) {
  28. result[k++] = right[j++];
  29. }
  30. return result;
  31. }
  32. public static void main(String[] args) {
  33. int[] arr = {38, 27, 43, 3, 9, 82, 10};
  34. int[] sortedArr = mergeSort(arr);
  35. System.out.println("排序后的数组: " + Arrays.toString(sortedArr));
  36. }
  37. }

复杂度分析

复杂度类型 具体复杂度 分析说明
时间复杂度 $O(n log n)$ 分解过程的时间复杂度为 $O(log n)$,因为每次都将数组分成两部分;合并过程的时间复杂度为 $O(n)$,因为需要遍历所有元素。综合起来,归并排序的时间复杂度为 $O(n log n)$。
空间复杂度 $O(n)$ 需要额外的空间来存储合并过程中的临时数组。
稳定性 稳定 在合并过程中,如果两个元素相等,会保持它们在原数组中的相对顺序。

实用性例子

假设有一个电商平台,需要对用户的购买金额进行排序,以便分析不同消费层次的用户分布。由于购买金额数据量可能较大,使用归并排序可以在较短的时间内完成排序,并且保证相同购买金额的用户顺序不变。

  1. # 模拟用户购买金额数据
  2. purchase_amounts = [120.5, 80.2, 200, 120.5, 50.3, 300]
  3. sorted_amounts = merge_sort(purchase_amounts)
  4. print("排序后的购买金额:", sorted_amounts)

总结

归并排序以其分治法的思想和稳定的排序特性,成为了排序算法中的经典之作。通过将问题分解为更小的子问题并逐步解决,归并排序能够高效地处理大规模数据。虽然它需要额外的空间来存储临时数组,但在大多数情况下,其 $O(n log n)$ 的时间复杂度使其成为一个非常实用的排序算法。无论是在学术研究还是实际应用中,归并排序都有着广泛的应用前景。希望通过本文的介绍,大家对归并排序有了更深入的理解,并能够熟练运用其代码实现。

归并排序 - 算法实现 - 归并排序的代码实现