学习笔记-数据结构与算法-归并排序

归并排序核心思想:

将一个数组一分二,然后将两个数组分别排序,最后将两个有序数据合并,就完成了归并排序。

学习笔记-数据结构与算法-归并排序_第1张图片

归并排序使用的是分治思想,分而治之,将一个大问题分解为n个小问题,小问题解决了,大问题也就解决了。

归并排序一般使用递归来实现,要写出递归代码的关键,写出递推公式,找到终止条件。

归并排序的递推公式:

merge_sort(p…r) = merge(merge_sort(p…q),merge_sort(q+1….r))

终止条件:q>= r

递推公式注释:

merge_sort(p…r)表示我们要排序的数组的下标在p…r区间,将这个大的数组的排序问题转化为了两个子数组排序的问题。即排序p到q区间和q+1到r区间,q=(p+r)/2,当这两个数组排序完成后,使用merge合并函数进行数组的合并,整个数组即可为有序。

再来说说merge合并函数

还是先画个图

 

学习笔记-数据结构与算法-归并排序_第2张图片

学习笔记-数据结构与算法-归并排序_第3张图片

学习笔记-数据结构与算法-归并排序_第4张图片

代码实现

public class MergerSort<T> implements SortInf<T> {

 
@Override
 
public void sort(T[] data) {

   
if (null == data || data.length <= 1) {
     
return;
   
}
   
if (!(data[0] instanceof Comparable)) {
     
throw new IllegalArgumentException("data not implement compator interface");
   
}

   
// 1,归并排序操作
   
recurstion(data, 0, data.length - 1);
 
}

 
private void recurstion(T[] data, int start, int end) {
   
// 递归的终止条件
   
if (start >= end) {
     
return;
   
}

   
// 1,找到中间的索引位置
   
int midIndex = (start + end) / 2;
   
// 进行左半边数据递归操作
   
recurstion(data, start, midIndex);
   
// 进行右半边数据递归操作
   
recurstion(data, midIndex + 1, end);

   
// 进行mergesort的合并操作
   
merget(data, start, midIndex, midIndex + 1, end);
 
}

 
/**
   *
进行数据的合并操作
  
*
   * @param
data 原始数据
  
* @param leftstart 左开始索引
  
* @param leftEnd 左结束索引
  
* @param rightStart 右边开始索引
  
* @param end 右边结束索引
  
*/
 
private void merget(T[] data, int leftstart, int leftEnd, int rightStart, int end) {

   
int dataLength = end - leftstart + 1;

   
// 声明一个目标的数组大小
   
T[] target = (T[]) Array.newInstance(data[0].getClass(), dataLength);
    int
tarIndex = 0;

    int
leftIndex = leftstart;
    int
rightIndex = rightStart;

    while
(leftIndex <= leftEnd && rightIndex <= end) {
     
// if i < j ? -1  == 0 > 1
     
if (((Comparable) data[leftIndex]).compareTo(data[rightIndex]) > 0) {
        target[tarIndex++] = data[rightIndex++]
;
     
} else {
        target[tarIndex++] = data[leftIndex++]
;
     
}
    }

   
// 将剩余的值拷贝到目标数组中
   
if (leftIndex <= leftEnd) {
     
for (int i = leftIndex; i <= leftEnd; i++) {
        target[tarIndex++] = data[i]
;
     
}
    }
else if (rightIndex <= end) {
     
for (int i = rightIndex; i <= end; i++) {
        target[tarIndex++] = data[i]
;
     
}
    }

   
// 将数据拷贝回原数组中
   
for (int i = leftstart; i <= end; i++) {
      data[i] = target[i - leftstart]
;
   
}

    System.
out.println(Arrays.toString(data));
 
}
}

 

如何分析归并排序的时间复杂度

在递归的场景中,一个问题a可以分解为几个子问题b和c,将问题b和问题c求解后,再将问题b和问题c的结果合并,就可以得到问题a的求解

定义求解的问题,a的时间为t(a),求解b、c的时间时间分为别t(b)和t(c),合并t(b)和t(c)的时间为k,代入递推公式就各要得到:

t(a)=t(b)+t(c)+k

在归并排序中,每次都将数据一分为二,可以表示为n/2,merge合并函数每次都需要将n个数据合并,可以表示为n,递推关系式可以改写为为:

t(n)=2*t(n/2)+n

t(1)=C,,当求解的数组大小为1时,只需要常量级的时间,所以表示为C

 

可获得结果

再次计算

结果

 

再次计算

结果

 

总结规律

 

可得到

可得到k的取值

t(1)=C

k代入

 

使用O表示法就是

 

归并排序的总结:

算法名称

最好情况时间复杂度

最好情况的原始数据

最坏情况时间复杂度

最坏情况的原始数据

平均情况时间复杂度

是否基于比较

空间复杂度

是否稳定排序算法

归并排序

O(nlogn)

与原始数据的有序度无关

O(nlogn)

与原始数据有序度无关

O(nlogn)

O(n)

非原地排序算法

移定的原地排序算法。

 

 

 

 

 

 

 

 

你可能感兴趣的:(数据结构与算法,学习笔记)