归并排序
递归
证书学习归并排序之前,我们得先学习一下递归算法。
定义:
定义方法时,在方法内部调用方法本身,称之为递归。
public void show(){
System.out.println("aaa");
show();
}
作用:
它通常把一个大型复杂的问题,层层转换为一个与原问题相似的,规模较小的问题来求解。递归策略只需要少量的程序就可以描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
注意事项:
在递归中,不能无限制的调用自己,必须要有边界条件,能够让递归结束,因为每一次递归调用都会在栈内存开辟新的空间,重新执行方法,如果递归的层级太深,很容易造成栈内存溢出。
package com.igeek.test;
public class Test01 {
public static void main(String[] args) {
//求n的阶乘
long result=factorial(5);
System.out.println(result);
}
public static long factorial(int n){
if (n==1){
return 1;
}
return n*factorial(n-1);
}
}
//结果:120
归并排序:
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将俩个有序表合并成一个有序表,称为二路归并。
需求:
排序前:{8,4,5,7,1,3,6,2}
排序后:{1,2,3,4,5,6,7,8}
归并排序原理:
1.尽可能的一组数据拆分成俩个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是1为止。
2.将相邻的俩个子组进行合并一个有序的大组。
3.不断的重复步骤2,直到最终只有一个组为止。
归并排序API设计:
归并原理:
归并排序的待码
package com.igeek.sort;
public class Merge {
//归并所需要的辅助数组
private static Comparable[] assist;
/*
比较v元素是否小于w元素
*/
private static boolean less(Comparable v,Comparable w){
return v.compareTo(w)<0;
}
/*
数组元素i和j交换位置
*/
private static void exch(Comparable[] a,int i,int j){
Comparable t=a[i];
a[i]=a[j];
a[j]=t;
}
/*
对数组a中的元素进行排序
*/
public static void sort(Comparable[] a){
//1.初始化辅助数组assist;
assist=new Comparable[a.length];
//2.定义一个lo变量,和hi变量,分别记录数组中最小的索引和最大的索引;
int lo=0;
int hi=a.length-1;
//3.调用sort重载方法完成数组a中,从索引lo到索引hi的元素的排序
sort(a,lo,hi);
}
/*
对数组a中从lo到hi的元素进行排序
*/
private static void sort(Comparable[] a,int lo,int hi){
//做安全性校验;
if (hi<=lo){
return;
}
//对lo到hi之间的数据进行分为俩个组
int mid=lo+(hi-lo)/2;
//分别对每一组数据进行排序
sort(a,lo,mid);
sort(a,mid+1,hi);
//再把俩个组中的数据进行归并
merge(a,lo,mid,hi);
}
/*
对数组中,从lo到mid为一组,从mid+1到hi为一组,对这俩组数据进行归并
*/
private static void merge(Comparable[] a,int lo,int mid,int hi){
//定义三个指针
int i=lo;
int p1=lo;
int p2=mid+1;
//遍历,移动p1指针和p2指针,比较对应索引处的值,找出小的那个,放在辅助数组的对应索引处
while (p1<=mid && p2<=hi){
//比较对应索引处的值
if(less(a[p1],a[p2])){
assist[i++]=a[p1++];
}else {
assist[i++]=a[p2++];
}
}
//遍历,如果p1的指针没有走完,那么顺序移动p1指针,把对应的元素放在辅助数组的对应索引处
while (p1<=mid){
assist[i++]=a[p1++];
}
//遍历,如果p1的指针没有走完,那么顺序移动p1指针,把对应的元素放在辅助数组的对应索引处
while (p2<=hi){
assist[i++]=a[p2++];
}
//把辅助数组中的元素拷贝到原数组中
for (int index=lo; index <=hi ; index++) {
a[index]=assist[index];
}
}
}
//测试:
package com.igeek.test;
import com.igeek.sort.Merge;
import java.util.Arrays;
public class MergeTest {
public static void main(String[] args) {
Integer[] a={2,4,1,5,7,8};
Merge.sort(a);
System.out.println(Arrays.toString(a));
}
}
//结果:{1,2,4,5,7,8}
归并排序的缺点:
需要申请额外的数组空间,导致空间复杂度提升,是典型的以空间换时间的操作