DS_【归并排序】
Java-四大排序
- 归并排序
归并的实现排序的一种解决方式,该算法直接体现分 和 治
归并排序过程描述
- 准备一个承载的数组该数组的长度与待排序的数组大小相同
- 排序的过程从小到大 先分组后排序
- 先把所有的数据两两分组 i=1 s1=0 e1=0 s2=1 e2=1 使用s1--e1 表示分组排的第一个数组s2---e2表示分组排的第二个 经过第一次 数组A 和数组 B中存放 arra[0] arr[1]
通过比较A与B中的元素在temArray按序排列
然后一起拿到下两个组放入A B 中进行同样的比较
经过第一次的分与治每个数字两两分组排列排序后的返回array中
- 第二次 i=2 s1=0 e2=1 s2=2 e3=3传入记为A B
对A B两个安排数组进行比较
- Array[s1]<Array[s2] array[s1]先存入tmpArray s1++ s1=1
- Array[s1]>Array[s2] array[s2]存入tmpArray s2++ s2=3
再重复(1)(2)
再传下下两个组
经过第二次 tmpArray 4 5 7 8 1 2 3 6
- 第三次i=4 传入 A s1=0 s2=3 Bs1=4 e2=7
非递归算法过程描述
i表示分组大小
- i=1 s1-e1 s2-e2 每个组一个元素 循环遍历两个组归并两个组
- i=2 每组2个元素
- i=4
- i=8
- 在比较时候 s1=0 e1=s1+gap(i)-1 s2=e1+1 e2=s2+gap(i)-1
两个组比较时while(start1<=end1&&start2<=end2){
if(array[start1]<=array[start2]){
tmpArray[i++] = array[start1++];
}else{
tmpArray[i++] = array[start2++];
}
}
while(start1<=end1){
tmpArray[i++] = array[start1++];
}
while(start2<=end2){
tmpArray[i++] = array[start2++];
}
(6)比较完成后start1 = end2+1;
end1 = start1+gap-1;
start2 = end1+1;
end2 = start2+gap-1>array.length-1?array.length-1:start2+gap-1;
代码实现
```javascript
public static void mergeSort_Un(int[] array){
long start = System.nanoTime();
for(int i=1;i<=array.length;i=2*i){
merge(array,i);
}
long end = System.nanoTime();
System.out.println("非递归归并排序时间"+(end-start)+"纳秒");
}
public static void merge(int[] array,int gap){
int[] tmpArray = new int[array.length];
int i=0; //tmpArray 的下标
int start1 = 0;
int end1 = start1+gap-1;
int start2 = end1+1;
int end2 = start2+gap-1>array.length-1?
array.length-1:start2+gap-1;
//保证有两个段
while(start2<array.length){
//两个归并段 在归并中 都要有数据
while(start1<=end1&&start2<=end2){
if(array[start1]<=array[start2]){
tmpArray[i++] = array[start1++];
}else{
tmpArray[i++] = array[start2++];
}
}
while(start1<=end1){
tmpArray[i++] = array[start1++];
}
while(start2<=end2){
tmpArray[i++] = array[start2++];
}
start1 = end2+1;
end1 = start1+gap-1;
start2 = end1+1;
end2 = start2+gap-1>array.length-1?array.length-1:start2+gap-1;
}
while(start1<=array.length-1){ //start1<=end1 加入最后一个数组 只有一个值 就会发生数组越界
tmpArray[i++] = array[start1++];
}
for (int j = 0; j < tmpArray.length; j++) {
array[j] = tmpArray[j];
}
}
```
时间
**********有序**********
非递归归并排序时间16557778纳秒
**********无序**********
非递归归并排序时间5777纳秒
递归实现归并算法
思路
- 通过 mid拿到一个组的中间下标
- mergeSort函数依次递归左边和右边
- mergeSort通过不断的调用自身继续分化
- 当所有的组分为只有一个元素时
- 然后不断地比较相邻的两个组的元素合并
- 实现成体排序
将所有的数据分分为若干组魅族的元素个数唯一
在进行合并时保证每一个组在合并时都有序
代码实现
```javascript
public static void merge(int[] array){
long s1 = System.nanoTime();
mergeSort(array,0,array.length-1);
long s2 = System.nanoTime();
System.out.println("归并排序递归时间"+(s2-s1)+"纳秒");
}
public static void mergeSort(int[] array,int start,int end){
if(start>=end){
return ;
}
int mid = (start+end)>>>1; //找到 中间
mergeSort(array,start,mid); //递归排序左边
mergeSort(array,mid+1,end);
//合并函数
mergeMethod(array,start,mid,end);
}
public static void mergeMethod(int[] array,int start,int mid,int end){
int[] tmpArr = new int[array.length];
int tmpIndex = start; //存放 tmpArr下标
int start2 = mid+1; //第二次归并 start
int i = start;
while(start<=mid&&start2<=end) { //进入 归并过程
if (array[start] <= array[start2]) { //如果 array[start] 小于 s2 将两个之中的小值 存入新建数组中
//新建数组与栈类似 又有 tmpIndex 表示 存放的下标
tmpArr[tmpIndex++] = array[start++]; //那个值小 存那个
} else {
tmpArr[tmpIndex++] = array[start2++];
}
}
while(start<=mid){
tmpArr[tmpIndex++] = array[start++];
}
while(start2<=end){
tmpArr[tmpIndex++] = array[start2++];
}
while(i<=end){
array[i] = tmpArr[i];
i++;
}
}
```
时间
**********有序**********
归并排序递归时间5453525777纳秒
**********无序**********
归并排序递归时间5756729333纳秒
总结
- 归并排序在实现时采用先分后合的思想性能优,比较类似于二叉树
- 空间复杂度 O(N) 每一次排序时都要申请开辟空间tmpArray
- 时间复杂度O(N*logN)
- 稳定性 稳定 不存在交换