归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用,将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
排序原理
1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是1为止。
2.将相邻的两个子组进行合并成一个有序的大组;
3.不断的重复2步骤,直到最终只有一个组为止;
基本思想:将待排序元素分成大小大致相同的2个子集合,分别对2个子集合进行排序,最终将排好序的子集合合并成为所要求的排好序的集合。
代码实现:
public class MergeSort {
public static void main(String[] args) {
int a[] = new int[5];
int temp[] = new int[a.length];
System.out.println("排序前:");
for (int i = 0; i < a.length; i++) {
int num = new Random().nextInt(10);
a[i] = num;
System.out.print(num + "\t");
}
sort(a,0,a.length-1,temp);
System.out.println("\n排序后:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+"\t");
}
}
/**
* 对每个分组进排序
* @param a 需要排序的数组
* @param low 每个左分组的首元素的索引
* @param mid 每个左分组的最后一个元素的索引,mid+1就是右分组的首元素的索引
* @param high 右分组的最后一个元素的索引
* @param temp 辅助数组
*/
public static void merge(int a[],int low,int mid,int high,int temp[]){
//定义三个索引,分别指向的是temp数组的首元素、左分组的首元素、右分组的首元素
int p1=0,p2 = low,p3 = mid + 1;
//两个分组的元素进行遍历比较,当有一个分组遍历完毕就退出
while (p2<=mid && p3 <= high){
//判断左分组的值是否小于右分组,如果小于就直接将小的值放入辅助数组
if (a[p2] < a[p3]){
temp[p1++] = a[p2++];
}
else {
temp[p1++] = a[p3++];
}
}
//由于刚刚遍历的时候,只要又一边的分组遍历完就退出了循环,
//因此需要遍历剩下还未遍历完的分组,将其剩下的元素放入辅助数组即可
while (p2 <= mid){ //如果是左分组未遍历完毕,就将左分组的剩下元素放入辅助数组
temp[p1++] = a[p2++];
}
while (p3 <= high){ //如果是右分组未遍历完毕,就将右分组的剩下元素放入辅助数组
temp[p1++] = a[p3++];
}
//由于我们将所有的有序值都放入的辅助数组中,因此需要将辅助数组中的值返回给原数组
for (int i = 0; i < p1; i++) {
a[low+i] = temp[i];
}
}
/**
*
* @param a 需要排序的数组
* @param low 每个分组的首元素的索引
* @param high 每个分组的最后一个元素的索引
* @param temp 辅助数组
*/
public static void sort(int a[],int low,int high,int temp[]){
//判断是否该分组分到每一个元素为一组的程度
if (low<high){
int mid = low+(high-low)/2; //定义一个中间遍历,作为分组的中间索引,用于进一步拆分
sort(a,low,mid,temp); //左分组
sort(a,mid+1,high,temp); //右分组
merge(a,low,mid,high,temp);
}
}
}
运行结果: