归并排序算法
个人理解
分治算法,虽然目前还不太理解,不过味道大概嗅到了一些
先一半一半的分开,然后到了 最小的不可分割的原子层面,进行比较,按顺序交换,这样就达到了最小分组层面的有序
然后往上回溯,回溯的时候呢,往上找,两个最小分组进行排序,只不过因为原本的数组已经有序了,我们可以放心的从左往右遍历。因此我们新开辟一份空间,搞一个数组,依次从左往右遍历两个最小分组,谁小复制谁即可。复制完成以后再重新拷贝回原本的数组空间即可。
分治
很多采用的是递归的方法进行的实现,但是这样有个缺点在于,当数据很大的时候栈会溢出
看到《大话数据结构》的一些讲解,讲到可以利用非递归方式进行实现
具体的实现思路是
整体类似插入排序
既然我们总是要找到最小的单位进行比较,不如直接从最小的单位开始了。反过来进行实现。(个人认为递归只是在数据大小不能提前确定的情况下采用,然而我们每次进行排序的序列都是可以提前知道数据量大小的,因此这类问题都可以进行逆向,采用非递归的方法进行实现)
那直接从最小的两个的进行比较,先两个进行插入排序,然后两个都是有序数列以后,再进行两个包含两个元素的有序数列的插入排序。然后再次扩展为两个包含四个元素的有序数列的插入排序。
总体思路
2个2个排序,完成后是 有序 2 2 2 2…孤儿
4个4个排序,完成后是 有序 4 4 4 4…孤儿
8个8个排序,完成后是 有序 8 8 8 8…孤儿
…
对于孤儿序列的处理方法,是和最后一个序列一起进行有序插入排序
代码写之
package sort;
import java.util.Arrays;
public class MergetSort
{
public static void main(String[] args)
{
int[] arr =
{ 9, 8, 7, 6, 5, 4, 3, 2, 1, 6 ,5,6,7,2,5,74,65,4,5,4,2,6};
System.out.println(Arrays.toString(arr));
System.out.println("---------------开始排序---------------");
MergeSort(arr);
}
/**
*
* @param arr 要插入排序的数组
* @param temp 临时存放的数组,用于整体赋值
* @param GroupLength 排序需要的数组长度
*/
public static void MergeSort(int[] arr)
{
int[] temp = new int[arr.length];
int GroupSize = 1;
int GroupNum = 0;
int left, right, mid;
while (GroupSize*2 < arr.length)
{
System.out.println("----------------"+GroupSize+"个一组"+"-------------------");
GroupNum = arr.length / GroupSize;
for (int i = 0; (i + 1) < GroupNum; i += 2)
{
left = i * GroupSize;
right = (i + 2) * GroupSize - 1;
mid = (left + right) / 2;
Merge(arr, temp, left, mid, right); // 当前分组和下一个分组进行合并
System.out.println(Arrays.toString(arr));
}
//最后还有个孤儿组,和最后一个组搞一搞
//8 3 0-7 3 5
left = (GroupNum-1)*GroupSize;//最后一个组的第一个
right = arr.length-1;//最后一个
mid = GroupNum*GroupSize-1;//最后一个组的最后一个
Merge(arr, temp, left, mid, right); // 当前分组和下一个分组进行合并
GroupSize *= 2; // 组的大小翻一番
}
//对最后一组进行处理
mid = GroupNum*GroupSize/2-1;
Merge(arr, temp, 0, mid, arr.length-1); // 当前分组和下一个分组进行合并
System.out.println("---------------最后一次---------------");
System.out.println(Arrays.toString(arr));
}
// 合并一个序列的两个有序数列,
//由于放进来的不是整个序列,因此需要指定序号
public static void Merge(int[] arr, int temp[], int left, int mid, int right)
{
int i = left;
int j = mid + 1;
int k = left;
while (i <= mid && j <= right)
{
if (arr[i] < arr[j])
{
temp[k++] = arr[i++];
} else
{
temp[k++] = arr[j++];
}
}
while (i <= mid)
{
temp[k++] = arr[i++];
}
while (j <= right)
{
temp[k++] = arr[j++];
}
// 复制回arr数组
for (int k2 = left; k2 <= right; k2++)
{
arr[k2] = temp[k2];
}
}
}