package sort;
/**
* 归并排序相比较之前的排序算法而言加入了分治法的思想,其算法思路如下:
*
* 1.如果给的数组只有一个元素的话,直接返回(也就是递归到最底层的一个情况)
*
* 2.把整个数组分为尽可能相等的两个部分(分)
*
* 3.对于两个被分开的两个部分进行整个归并排序(治)
*
* 4.把两个被分开且排好序的数组拼接在一起
*/
public class Merge<T extends Comparable<T>> {
public void mergeArr(T[] arr, int l, int mid, int r){
T[] aux = (T[])(new Object[r - l + 1]);
for(int i = l; i <= r; i++)
aux[i - l] = arr[i];
//双指针操作
int i = l, j = mid + 1;
for(int k = l; k <= r; k++){
if(i > mid){
arr[k] = aux[j - l];
j++;
}else if(j > r){
arr[k] = aux[i - l];
i++;
}else if(aux[i-l].compareTo(aux[j - l]) < 0){
arr[k] = aux[i - l];
i ++;
}else{
arr[k] = aux[j - l];
j ++;
}
}
}
//递归使用递归排序, 对arr[l...r]的范围进行排序
public void merge(T[] arr, int l, int r){
// if( l >= r)
// return;
if(r - l <= 15){
insertionSort(arr, l, r);
return;
}
int mid = (l + r) / 2;
merge(arr, l, mid);
merge(arr, mid + 1, r);
if(arr[mid].compareTo(arr[mid + 1]) > 0)
mergeArr(arr, l, mid, r);
}
private void insertionSort(T[] arr, int l, int r) {
for(int i = l + 1; i <= r; i++){
T t = arr[i];
int j;
//依次循环将数据后移一个位置, 最后在插入
for(j = i; j > l && arr[j - 1].compareTo(t) > 0; j--)
arr[j] = arr[j - 1];
arr[j - 1] = t;
}
return;
}
public void mergeSort(T[] arr, int n){
merge(arr, 0, n - 1);
}
/**
* 以下是经典的归并排序算法
* @param arr 数组
* @param l 左边界
* @param r 右边界
*/
void mergeSort(int[] arr, int l, int r) {
if (l < r) {
int m = l+(r-l)/2;
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, m, r);
}
}
private void merge(int[] arr, int l, int m, int r) {
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
int[] L = new int[n1];
int[] R = new int[n2];
/*
拷贝新数组
*/
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1+ j];
i = 0;
j = 0;
k = l;
/*
* 对两个数组在不越界的情况下,分别拷贝数组直到一个数组越界
*/
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
}else {
arr[k] = R[j];
j++;
}
k++;
}
/*
将不越界的数组拷贝到新数组中
*/
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
}