归并排序思想
归并排序主要思想是把一个无序数组一直分解,直到只有一个元素的若干个数组为止;然后再两两(两个数组)合并,合并的时候分别遍历对应的元素,选择小的放入temp数组中,遍历合并完成后,如果某个数组中还有元素,直接合并到temp数组末尾,最后将temp数组覆盖原数组。
可以使用递归或者迭代的方式来实现,大话数据结构中提到迭代消耗时间更少,并且空间占用更少,是递归的优化
递归方式:
package com.sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class MergeSort {
public static void main(String[] args) {
// int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
// int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
// int[] arr = {8, 4, 5, 7, 1, 3, 6};
// mergeSort2(arr, new int[arr.length]);
// System.out.println(Arrays.toString(arr));
int[] randomArray = new int[80000000];
for (int i = 0; i < randomArray.length; i++) {
randomArray[i] = (int) (Math.random() * 800000000);
}
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS");
String formatted = simpleDateFormat.format(date);
System.out.println("排序前的时间:" + formatted);
mergeSort(randomArray, 0, randomArray.length - 1, new int[randomArray.length]);
Date dateAfter = new Date();
String dateAfterFormat = simpleDateFormat.format(dateAfter);
System.out.println("排序后的时间:" + dateAfterFormat);
}
public 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, mid, right, temp);
}
}
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int l = left;
int r = mid + 1;
int t = 0;
while (l <= mid && r <= right) {
// 如果左边取的值比右边小,那么将其放入temp数组,反之亦然
if (arr[l] < arr[r]) {
temp[t] = arr[l];
l++;
} else {
temp[t] = arr[r];
r++;
}
t++;
}
// 查看左边是否还有未填进数组的数,将其遍历进数组
while (l <= mid) {
temp[t] = arr[l];
t++;
l++;
}
// 查看右边是否还有未填进数组的数,将其遍历进数组
while (r <= right) {
temp[t] = arr[r];
t++;
r++;
}
t = 0;
// 覆盖原数组
while (left <= right) {
arr[left] = temp[t];
left++;
t++;
}
}
}
迭代方式
按照大话数据结构的没写完整~_~,对于处理每次迭代末尾的数组有问题,奇数大小的数组的最后一个元素我无法实现归并,就在完成归并后实现了一个直接插入,理论上增加了一定的时间复杂度,因为要移动数据。但是经过测试,不处理末尾的元素和使用直接插入去处理,时间几乎相同,都在几十毫秒之间波动。
package com.sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class MergeSort {
public static void main(String[] args) {
// int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
// int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
// int[] arr = {8, 4, 5, 7, 1, 3, 6};
// mergeSort2(arr, new int[arr.length]);
// System.out.println(Arrays.toString(arr));
int[] randomArray = new int[80000000];
for (int i = 0; i < randomArray.length; i++) {
randomArray[i] = (int) (Math.random() * 800000000);
}
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS");
String formatted = simpleDateFormat.format(date);
System.out.println("排序前的时间:" + formatted);
mergeSort2(randomArray, new int[randomArray.length]);
Date dateAfter = new Date();
String dateAfterFormat = simpleDateFormat.format(dateAfter);
System.out.println("排序后的时间:" + dateAfterFormat);
}
public static void mergeSort2(int[] arr, int[] temp) {
int k = 1;
while (k <= arr.length) {
mergePass(arr, k, temp);
k *= 2;
}
int insertIndex = arr.length - 2;
// 处理尾数,将尾数并进上一个数组中
if (insertIndex < arr.length - 1) {
int insertValue = arr[insertIndex + 1];
// 直接把末尾这个数插入前一个数组中
while (insertIndex >= 0 && arr[insertIndex] > insertValue) {
arr[insertIndex+1] = arr[insertIndex];
insertIndex--;
}
arr[insertIndex+1] = insertValue;
}
}
// 间隔k来归并
public static void mergePass(int[] arr, int k, int[] temp) {
int i = 0;
int left = i, mid, right;
while (i <= arr.length - 2 * k) {
left = i;
right = i + 2 * k - 1;
mid = (left + right) / 2;
merge(arr, left, mid, right, temp);
i = i + 2 * k;
}
}
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int l = left;
int r = mid + 1;
int t = 0;
while (l <= mid && r <= right) {
// 如果左边取的值比右边小,那么将其放入temp数组,反之亦然
if (arr[l] < arr[r]) {
temp[t] = arr[l];
l++;
} else {
temp[t] = arr[r];
r++;
}
t++;
}
// 查看左边是否还有未填进数组的数,将其遍历进数组
while (l <= mid) {
temp[t] = arr[l];
t++;
l++;
}
// 查看右边是否还有未填进数组的数,将其遍历进数组
while (r <= right) {
temp[t] = arr[r];
t++;
r++;
}
t = 0;
// 覆盖原数组
while (left <= right) {
arr[left] = temp[t];
left++;
t++;
}
}
}