归并排序(经典)

思路分析

归并排序是利用归并的思想实现的排序方法,该算法采用经典的分治[^5]策略。

图解

image-20241101153840659

代码流程图

image-20241101153840659

提示+代码思路

  1. 归并排序执行次数为N-1次,N为数据量大小,即merge方法执行的次数。
  2. 由图解可知,我们需要完成“”和“”两个步骤:
    • 治,也就是合并merge的过程
    • merge需要参数为——int[] arr、left、right、mid、int[] temp
    • arr为原数组
    • left为待合并数据的左边位置、right为待合并数据的右边位置
    • mid=(left+right)/2
    • temp为临时数组
      1. merge是是对两个有序数组合并的过程(见红色箭头),单个元素的数组无疑是有序的。
      2. 合并时,需要有一个i、j分别代表左数组和右数组,依次比较,将小的那个元素放入到临时数组temp中
      3. 然后将左(或右)数组中剩余元素放入到temp中
      4. 最后将temp中元素拷贝到arr中
    • 分,也就是不断将大问题化为小问题的过程:
    • 如果传入参数left<right,就不断向左、右递归,进行拆分。
      1. mergeSort进行左右递归即可:
      2. mergeSort(arr,left,mid,temp)
      3. mergeSort(arr,mid+1,right,temp)
      4. merge(left,right)

代码实现

测试数据大小 花费时间(单位:毫秒)
10000 2
50000 7
80000 18
140000 22
500000 57
900000 93

MergeSort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.yukinoshita.algorithm.sort;

import java.util.Arrays;
import java.util.Random;

public class MergeSort {
public static void main(String args[]) {
int[] arr = {8, 5, 3, 7, 6, 2, 4, 1};
int[] temp = new int[arr.length];//需要一个额外的空间开销

System.out.println("排序前:" + Arrays.toString(arr));
mergeSort(arr, 0, arr.length - 1, temp);
System.out.println("排序后:" + Arrays.toString(arr));

// 测试算法性能
testPerformance();
}

private static void mergeSort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2;//中间索引
mergeSort(arr, left, mid, temp);//向左递归--分
mergeSort(arr, mid + 1, right, temp);//向右递归--分
merge(arr, left, right, mid, temp);
}
}

public static void merge(int[] arr, int left, int right, int mid, int[] temp) {
int i = left;//左边有序数组索引
int j = mid + 1;//右边有序数组索引
int t = 0;//临时数组temp所指

//两个有序数组比较、放入temp
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[t++] = arr[i++];
} else {
temp[t++] = arr[j++];
}
}

//将其中一个剩余的放入temp
while (i <= mid) {
temp[t++] = arr[i++];
}
while (j <= right) {
temp[t++] = arr[j++];
}

//将temp拷贝到arr
int k = left;
t = 0;
while (k <= right) {
arr[k++] = temp[t++];
}
}

// 测试算法性能的方法
public static void testPerformance() {
int size = 900000; // 数组大小
int[] arr = new int[size];
int[] temp = new int[size];
Random random = new Random();

// 生成无序数组
for (int i = 0; i < size; i++) {
arr[i] = random.nextInt(100000); // 随机数范围可以根据需要调整
}

long startTime = System.currentTimeMillis(); // 记录开始时间
mergeSort(arr, 0, arr.length - 1, temp); // 排序
long endTime = System.currentTimeMillis(); // 记录结束时间

System.out.println("排序大小: " + size);
System.out.println("排序时间: " + (endTime - startTime) + " 毫秒");
}


}